@kody-ade/kody-engine 0.4.409 → 0.4.410

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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +155 -97
  2. package/package.json +1 -1
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.409",
18
+ version: "0.4.410",
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",
@@ -2219,6 +2219,108 @@ var init_convex_client = __esm({
2219
2219
  }
2220
2220
  });
2221
2221
 
2222
+ // src/kody-api-client.ts
2223
+ import { getFunctionName } from "convex/server";
2224
+ function apiUrl(env) {
2225
+ return (env.KODY_API_URL?.trim() || DEFAULT_KODY_API_URL).replace(/\/$/, "");
2226
+ }
2227
+ function oidcRequestUrl(env) {
2228
+ const raw = env.ACTIONS_ID_TOKEN_REQUEST_URL?.trim();
2229
+ if (!raw) throw new Error("GitHub Actions OIDC request URL is unavailable");
2230
+ const url = new URL(raw);
2231
+ if (url.protocol !== "https:") throw new Error("GitHub Actions OIDC request URL must use HTTPS");
2232
+ url.searchParams.set("audience", OIDC_AUDIENCE);
2233
+ return url;
2234
+ }
2235
+ function tokenExpiry(token) {
2236
+ try {
2237
+ const payload = JSON.parse(Buffer.from(token.split(".")[1] ?? "", "base64url").toString("utf8"));
2238
+ return typeof payload.exp === "number" ? payload.exp * 1e3 : Date.now() + 4 * 6e4;
2239
+ } catch {
2240
+ return Date.now() + 4 * 6e4;
2241
+ }
2242
+ }
2243
+ async function githubOidcToken(env, force = false) {
2244
+ if (!force && cachedToken && cachedToken.expiresAt - 6e4 > Date.now()) return cachedToken.value;
2245
+ const requestToken = env.ACTIONS_ID_TOKEN_REQUEST_TOKEN?.trim();
2246
+ if (!requestToken) throw new Error("GitHub Actions OIDC request token is unavailable");
2247
+ const response = await fetch(oidcRequestUrl(env), {
2248
+ headers: { Authorization: `Bearer ${requestToken}` },
2249
+ signal: AbortSignal.timeout(15e3)
2250
+ });
2251
+ if (!response.ok) throw new Error(`GitHub Actions identity request failed (${response.status})`);
2252
+ const body = await response.json();
2253
+ if (typeof body.value !== "string" || !body.value) throw new Error("GitHub Actions identity response was invalid");
2254
+ cachedToken = { value: body.value, expiresAt: tokenExpiry(body.value) };
2255
+ return body.value;
2256
+ }
2257
+ function operationName(fn) {
2258
+ return getFunctionName(fn).replace(":", ".");
2259
+ }
2260
+ async function callKodyApi(kind, fn, args, env) {
2261
+ const call = async (forceToken) => {
2262
+ const token = await githubOidcToken(env, forceToken);
2263
+ return fetch(`${apiUrl(env)}/api/kody/engine/backend`, {
2264
+ method: "POST",
2265
+ headers: {
2266
+ Authorization: `Bearer ${token}`,
2267
+ "Content-Type": "application/json"
2268
+ },
2269
+ body: JSON.stringify({ kind, operation: operationName(fn), args }),
2270
+ signal: AbortSignal.timeout(3e4)
2271
+ });
2272
+ };
2273
+ let response = await call(false);
2274
+ if (response.status === 401) response = await call(true);
2275
+ if (!response.ok) throw new Error(`Kody backend request failed (${response.status})`);
2276
+ const body = await response.json();
2277
+ return body.result;
2278
+ }
2279
+ function hasGitHubActionsIdentity(env = process.env) {
2280
+ return Boolean(
2281
+ env.GITHUB_ACTIONS === "true" && env.ACTIONS_ID_TOKEN_REQUEST_URL?.trim() && env.ACTIONS_ID_TOKEN_REQUEST_TOKEN?.trim()
2282
+ );
2283
+ }
2284
+ function createKodyApiBackendClient(env = process.env) {
2285
+ if (!hasGitHubActionsIdentity(env)) throw new Error("GitHub Actions workflow identity is unavailable");
2286
+ return {
2287
+ query: (fn, args) => callKodyApi("query", fn, args, env),
2288
+ mutation: (fn, args) => callKodyApi("mutation", fn, args, env)
2289
+ };
2290
+ }
2291
+ async function readRuntimeSecretFromKody(name, env = process.env) {
2292
+ const token = await githubOidcToken(env);
2293
+ const response = await fetch(`${apiUrl(env)}/api/kody/engine/secret`, {
2294
+ method: "POST",
2295
+ headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json" },
2296
+ body: JSON.stringify({ name }),
2297
+ signal: AbortSignal.timeout(3e4)
2298
+ });
2299
+ if (response.status === 404) return null;
2300
+ if (!response.ok) throw new Error(`Kody secret request failed (${response.status})`);
2301
+ const body = await response.json();
2302
+ return typeof body.value === "string" ? body.value : null;
2303
+ }
2304
+ async function readPreviewContextFromKody(env = process.env) {
2305
+ const token = await githubOidcToken(env);
2306
+ const response = await fetch(`${apiUrl(env)}/api/kody/engine/preview-context`, {
2307
+ method: "POST",
2308
+ headers: { Authorization: `Bearer ${token}` },
2309
+ signal: AbortSignal.timeout(3e4)
2310
+ });
2311
+ if (!response.ok) throw new Error(`Kody preview context request failed (${response.status})`);
2312
+ return await response.json();
2313
+ }
2314
+ var DEFAULT_KODY_API_URL, OIDC_AUDIENCE, cachedToken;
2315
+ var init_kody_api_client = __esm({
2316
+ "src/kody-api-client.ts"() {
2317
+ "use strict";
2318
+ DEFAULT_KODY_API_URL = "https://kody-dashboard-khaki.vercel.app";
2319
+ OIDC_AUDIENCE = "kody-api";
2320
+ cachedToken = null;
2321
+ }
2322
+ });
2323
+
2222
2324
  // src/state-backend.ts
2223
2325
  import { anyApi } from "convex/server";
2224
2326
  function requireTenant(tenantId2) {
@@ -2236,10 +2338,16 @@ function requireNonEmpty(value, name) {
2236
2338
  return normalized;
2237
2339
  }
2238
2340
  function createStateBackendFromEnv(env = process.env, client) {
2239
- const url = env.CONVEX_URL?.trim();
2240
- const serviceKey = env.KODY_SERVICE_KEY?.trim();
2241
- if (!url || !serviceKey) throw new Error("CONVEX_URL and KODY_SERVICE_KEY are required");
2242
- const transport = client ?? createConvexClientFromEnv(env);
2341
+ let transport = client;
2342
+ if (!transport && hasGitHubActionsIdentity(env)) transport = createKodyApiBackendClient(env);
2343
+ if (!transport) {
2344
+ const url = env.CONVEX_URL?.trim();
2345
+ const serviceKey = env.KODY_SERVICE_KEY?.trim();
2346
+ if (!url || !serviceKey) {
2347
+ throw new Error("GitHub Actions identity or direct Kody backend credentials are required");
2348
+ }
2349
+ transport = createConvexClientFromEnv(env);
2350
+ }
2243
2351
  return {
2244
2352
  async get(tenantId2, taskKey, kind) {
2245
2353
  const result = await transport.query(anyApi.taskState.get, {
@@ -2412,10 +2520,14 @@ function createStateBackendFromEnv(env = process.env, client) {
2412
2520
  }
2413
2521
  };
2414
2522
  }
2523
+ function hasStateBackendConfig(env = process.env) {
2524
+ return hasGitHubActionsIdentity(env) || Boolean(env.CONVEX_URL?.trim() && env.KODY_SERVICE_KEY?.trim());
2525
+ }
2415
2526
  var init_state_backend = __esm({
2416
2527
  "src/state-backend.ts"() {
2417
2528
  "use strict";
2418
2529
  init_convex_client();
2530
+ init_kody_api_client();
2419
2531
  }
2420
2532
  });
2421
2533
 
@@ -3699,12 +3811,10 @@ function verifyTaskArtifacts(absDir) {
3699
3811
  }
3700
3812
  async function persistTaskArtifactsToState(config, _cwd, artifacts) {
3701
3813
  const tenantId2 = config.github?.owner && config.github.repo ? `${config.github.owner}/${config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim();
3702
- if (process.env.GITHUB_ACTIONS === "true" && (!process.env.CONVEX_URL || !process.env.KODY_SERVICE_KEY || !tenantId2)) {
3703
- throw new Error(
3704
- "Convex artifact backend is required in GitHub Actions (CONVEX_URL, KODY_SERVICE_KEY, and repository identity)"
3705
- );
3814
+ if (process.env.GITHUB_ACTIONS === "true" && (!hasStateBackendConfig() || !tenantId2)) {
3815
+ throw new Error("Kody backend access and repository identity are required in GitHub Actions");
3706
3816
  }
3707
- if (process.env.CONVEX_URL && process.env.KODY_SERVICE_KEY && tenantId2) {
3817
+ if (hasStateBackendConfig() && tenantId2) {
3708
3818
  const backend = createStateBackendFromEnv();
3709
3819
  for (const file of TASK_ARTIFACT_FILES) {
3710
3820
  const full = path11.join(artifacts.absDir, file);
@@ -5834,7 +5944,7 @@ var init_loadMemoryContext = __esm({
5834
5944
  loadMemoryContext = async (ctx) => {
5835
5945
  if (typeof ctx.data.memoryContext === "string") return;
5836
5946
  const tenantId2 = ctx.config.github?.owner && ctx.config.github.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : process.env.GITHUB_REPOSITORY?.trim();
5837
- if (process.env.CONVEX_URL && process.env.KODY_SERVICE_KEY && tenantId2) {
5947
+ if (hasStateBackendConfig() && tenantId2) {
5838
5948
  try {
5839
5949
  const backend = createStateBackendFromEnv();
5840
5950
  const docs = await backend.listRepoDocs(tenantId2, "memory:");
@@ -9535,7 +9645,7 @@ function subjectCandidates(kind, id, state) {
9535
9645
  return [...ids].map((candidate) => ({ kind, id: candidate }));
9536
9646
  }
9537
9647
  async function firstTrustOverride(ctx, subjects) {
9538
- const backendConfigured = Boolean(process.env.CONVEX_URL?.trim() && process.env.KODY_SERVICE_KEY?.trim());
9648
+ const backendConfigured = hasStateBackendConfig();
9539
9649
  if (!backendConfigured) return null;
9540
9650
  const repoSlug = ctx.config.github?.owner && ctx.config.github?.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : "";
9541
9651
  for (const subject of subjects) {
@@ -9751,6 +9861,7 @@ var init_advanceManagedGoal = __esm({
9751
9861
  init_typeDefinitions();
9752
9862
  init_issue();
9753
9863
  init_registry();
9864
+ init_state_backend();
9754
9865
  init_trustPolicy();
9755
9866
  init_workflowDefinitions();
9756
9867
  init_goalCapabilityScheduling();
@@ -10048,12 +10159,12 @@ function resolveTrigger(force) {
10048
10159
  }
10049
10160
  async function appendActivity(ctx, record2) {
10050
10161
  const tenantId2 = ctx.config.github?.owner && ctx.config.github.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : process.env.GITHUB_REPOSITORY;
10051
- if (process.env.CONVEX_URL?.trim() && process.env.KODY_SERVICE_KEY?.trim() && tenantId2) {
10162
+ if (hasStateBackendConfig() && tenantId2) {
10052
10163
  await createStateBackendFromEnv().appendDailyLog(tenantId2, "activity", record2.ts.slice(0, 10), record2);
10053
10164
  return;
10054
10165
  }
10055
10166
  if (process.env.GITHUB_ACTIONS === "true") {
10056
- throw new Error("Convex backend is required for company activity in GitHub Actions");
10167
+ throw new Error("Kody backend access is required for company activity in GitHub Actions");
10057
10168
  }
10058
10169
  }
10059
10170
  var appendCompanyActivity;
@@ -14773,6 +14884,18 @@ function envSecret(name, env) {
14773
14884
  }
14774
14885
  async function resolveRuntimeSecret(name, ctx, opts = {}) {
14775
14886
  const env = opts.env ?? process.env;
14887
+ if (hasGitHubActionsIdentity(env)) {
14888
+ try {
14889
+ const value = await readRuntimeSecretFromKody(name, env);
14890
+ return value ? { value, source: "vault" } : envSecret(name, env);
14891
+ } catch (err) {
14892
+ const fallback = envSecret(name, env);
14893
+ return {
14894
+ ...fallback,
14895
+ warning: `Kody secret read failed for ${name}: ${err instanceof Error ? err.message : String(err)}`
14896
+ };
14897
+ }
14898
+ }
14776
14899
  const masterRaw = env.KODY_MASTER_KEY?.trim() ?? "";
14777
14900
  if (!masterRaw || !env.CONVEX_URL?.trim() || !env.KODY_SERVICE_KEY?.trim()) return envSecret(name, env);
14778
14901
  try {
@@ -14800,6 +14923,7 @@ var init_runtimeSecrets = __esm({
14800
14923
  "src/scripts/runtimeSecrets.ts"() {
14801
14924
  "use strict";
14802
14925
  init_backendVault();
14926
+ init_kody_api_client();
14803
14927
  init_keys();
14804
14928
  }
14805
14929
  });
@@ -16618,7 +16742,7 @@ var init_publishReport = __esm({
16618
16742
  });
16619
16743
  const runId = generatedAt.replace(/\.\d{3}Z$/, "Z").replace(/:/g, "-");
16620
16744
  const tenantId2 = ctx.config.github?.owner && ctx.config.github.repo ? `${ctx.config.github.owner}/${ctx.config.github.repo}` : process.env.GITHUB_REPOSITORY;
16621
- if (process.env.CONVEX_URL?.trim() && process.env.KODY_SERVICE_KEY?.trim() && tenantId2) {
16745
+ if (hasStateBackendConfig() && tenantId2) {
16622
16746
  await createStateBackendFromEnv().saveReport(
16623
16747
  tenantId2,
16624
16748
  slug,
@@ -16634,7 +16758,7 @@ var init_publishReport = __esm({
16634
16758
  generatedAt
16635
16759
  );
16636
16760
  } else if (process.env.GITHUB_ACTIONS === "true") {
16637
- throw new Error("Convex backend is required for reports in GitHub Actions");
16761
+ throw new Error("Kody backend access is required for reports in GitHub Actions");
16638
16762
  }
16639
16763
  };
16640
16764
  }
@@ -17447,53 +17571,14 @@ function basePreviewAppName(repo) {
17447
17571
  }
17448
17572
  return `kp-${shortHash(owner)}-${shortHash(name)}-base`;
17449
17573
  }
17450
- function decryptVaultPayload(payload, keyRaw) {
17451
- const parts = payload.split(":");
17452
- if (parts.length !== 4 || parts[0] !== "v1") {
17453
- throw new Error("invalid vault payload format");
17454
- }
17455
- const [, ivB64, ctB64, tagB64] = parts;
17456
- const key = decodeMasterKey(keyRaw);
17457
- if (key.length !== 32) {
17458
- throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
17459
- }
17460
- const iv = Buffer.from(ivB64, "base64");
17461
- const ct = Buffer.from(ctB64, "base64");
17462
- const tag = Buffer.from(tagB64, "base64");
17463
- const decipher = createDecipheriv2("aes-256-gcm", key, iv);
17464
- decipher.setAuthTag(tag);
17465
- return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
17466
- }
17467
- function decodeMasterKey(keyRaw) {
17468
- if (/^[0-9a-fA-F]{64}$/.test(keyRaw)) return Buffer.from(keyRaw, "hex");
17469
- return Buffer.from(keyRaw.replace(/-/g, "+").replace(/_/g, "/"), "base64");
17470
- }
17471
- function derivePreviewVerifyKey(masterKeyRaw) {
17472
- const masterKey = decodeMasterKey(masterKeyRaw);
17473
- if (masterKey.length !== 32) {
17474
- throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
17475
- }
17476
- return Buffer.from(hkdfSync2("sha256", masterKey, Buffer.alloc(0), PREVIEW_KEY_INFO, 32)).toString("hex");
17477
- }
17478
17574
  function previewRuntimeEnv(args) {
17479
17575
  return {
17480
17576
  ...args.buildEnv,
17481
- KODY_PREVIEW_VERIFY_KEY: derivePreviewVerifyKey(args.masterKey),
17577
+ KODY_PREVIEW_VERIFY_KEY: args.previewVerifyKey,
17482
17578
  KODY_REPO_CONTEXT: args.repo,
17483
17579
  KODY_PR: String(args.pr)
17484
17580
  };
17485
17581
  }
17486
- function buildEnvFromVault(doc) {
17487
- const buildEnv = {};
17488
- for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
17489
- if (!entry?.value) continue;
17490
- if (NEVER_PASS_TO_BUILD.has(name)) continue;
17491
- buildEnv[name] = entry.value;
17492
- }
17493
- const raw = doc.secrets?.KODY_PREVIEW_BUILD_MODE?.value;
17494
- const buildMode = raw?.toLowerCase().trim() === "dev" ? "dev" : "prod";
17495
- return { buildEnv, buildMode };
17496
- }
17497
17582
  function formatPreviewComment(args) {
17498
17583
  return [
17499
17584
  "<!-- kody-fly-preview -->",
@@ -17505,23 +17590,9 @@ function formatPreviewComment(args) {
17505
17590
  function defaultImageTag(repo, ref) {
17506
17591
  return createHash4("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
17507
17592
  }
17508
- var NEVER_PASS_TO_BUILD, PREVIEW_KEY_INFO;
17509
17593
  var init_previewBuildHelpers = __esm({
17510
17594
  "src/scripts/previewBuildHelpers.ts"() {
17511
17595
  "use strict";
17512
- NEVER_PASS_TO_BUILD = /* @__PURE__ */ new Set([
17513
- "FLY_API_TOKEN",
17514
- "FLY_ORG_SLUG",
17515
- "FLY_DEFAULT_REGION",
17516
- "KODY_MASTER_KEY",
17517
- // Preview-config knob; consumed by the dispatcher before spawn.
17518
- "KODY_PREVIEW_BUILD_MODE",
17519
- "KODY_PREVIEW_VERIFY_KEY",
17520
- "KODY_REPO_CONTEXT",
17521
- "KODY_PR",
17522
- "KODY_BRANCH"
17523
- ]);
17524
- PREVIEW_KEY_INFO = "kody-preview:v1";
17525
17596
  }
17526
17597
  });
17527
17598
 
@@ -17630,16 +17701,6 @@ function flyHeaders(token) {
17630
17701
  "Content-Type": "application/json"
17631
17702
  };
17632
17703
  }
17633
- async function fetchVaultDoc(repo, masterKey) {
17634
- const [owner, name] = repo.split("/", 2);
17635
- if (!owner || !name) throw new Error(`invalid GITHUB_REPOSITORY "${repo}"`);
17636
- const record2 = await createStateBackendFromEnv().getRepoDoc(`${owner}/${name}`, "secrets.enc");
17637
- const raw = record2?.doc;
17638
- const payload = raw && typeof raw === "object" && !Array.isArray(raw) && typeof raw.ciphertext === "string" ? raw.ciphertext : "";
17639
- if (!payload) throw new Error("backend vault is empty \u2014 save secrets from the dashboard first");
17640
- const plaintext = decryptVaultPayload(payload, masterKey);
17641
- return JSON.parse(plaintext);
17642
- }
17643
17704
  async function flyAppExists(name, token) {
17644
17705
  const res = await fetch(`${FLY_MACHINES}/apps/${encodeURIComponent(name)}`, {
17645
17706
  headers: flyHeaders(token),
@@ -17814,7 +17875,7 @@ var FLY_MACHINES, FLY_GRAPHQL, REQ_TIMEOUT_MS2, runPreviewBuild;
17814
17875
  var init_runPreviewBuild = __esm({
17815
17876
  "src/scripts/runPreviewBuild.ts"() {
17816
17877
  "use strict";
17817
- init_state_backend();
17878
+ init_kody_api_client();
17818
17879
  init_previewBuildHelpers();
17819
17880
  init_previewBuildNamespace();
17820
17881
  init_previewBuildRun();
@@ -17831,12 +17892,10 @@ var init_runPreviewBuild = __esm({
17831
17892
  }
17832
17893
  let repo;
17833
17894
  let ref;
17834
- let masterKey;
17835
17895
  let ghToken3;
17836
17896
  try {
17837
17897
  repo = required("GITHUB_REPOSITORY");
17838
17898
  ref = required("GITHUB_SHA");
17839
- masterKey = required("KODY_MASTER_KEY");
17840
17899
  ghToken3 = (process.env.KODY_TOKEN ?? process.env.GH_TOKEN ?? process.env.GITHUB_TOKEN ?? process.env.GH_PAT ?? "").trim();
17841
17900
  if (!ghToken3) {
17842
17901
  throw new Error("GitHub auth token missing (KODY_TOKEN / GH_TOKEN / GITHUB_TOKEN / GH_PAT all empty)");
@@ -17850,17 +17909,17 @@ var init_runPreviewBuild = __esm({
17850
17909
  const appName = previewAppName(repo, pr);
17851
17910
  const tag = defaultImageTag(repo, ref);
17852
17911
  try {
17853
- const doc = await fetchVaultDoc(repo, masterKey);
17854
- const { buildEnv, buildMode } = buildEnvFromVault(doc);
17855
- const flyToken = doc.secrets?.FLY_API_TOKEN?.value?.trim();
17912
+ const previewContext = await readPreviewContextFromKody();
17913
+ const { buildEnv, buildMode } = previewContext;
17914
+ const flyToken = previewContext.flyApiToken?.trim();
17856
17915
  if (!flyToken) {
17857
17916
  ctx.output.exitCode = 99;
17858
17917
  ctx.output.reason = "runPreviewBuild: vault has no FLY_API_TOKEN \u2014 add it via the dashboard's /secrets page";
17859
17918
  return;
17860
17919
  }
17861
- const orgSlug = doc.secrets?.FLY_ORG_SLUG?.value?.trim() || (process.env.FLY_ORG_SLUG ?? "personal").trim();
17862
- const region = doc.secrets?.FLY_DEFAULT_REGION?.value?.trim() || (process.env.FLY_REGION ?? "fra").trim();
17863
- const nscTenantId = doc.secrets?.NSC_TENANT_ID?.value?.trim() || "";
17920
+ const orgSlug = previewContext.flyOrgSlug?.trim() || (process.env.FLY_ORG_SLUG ?? "personal").trim();
17921
+ const region = previewContext.flyRegion?.trim() || (process.env.FLY_REGION ?? "fra").trim();
17922
+ const nscTenantId = previewContext.namespaceTenantId?.trim() || "";
17864
17923
  console.log(`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`);
17865
17924
  if (Object.keys(buildEnv).length > 0) {
17866
17925
  const lines = Object.entries(buildEnv).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
@@ -17942,7 +18001,7 @@ var init_runPreviewBuild = __esm({
17942
18001
  appName,
17943
18002
  region,
17944
18003
  image: `registry.fly.io/${appName}:${tag}`,
17945
- env: previewRuntimeEnv({ buildEnv, masterKey, pr, repo })
18004
+ env: previewRuntimeEnv({ buildEnv, previewVerifyKey: previewContext.previewVerifyKey, pr, repo })
17946
18005
  },
17947
18006
  flyToken
17948
18007
  );
@@ -19725,10 +19784,10 @@ async function hydrateWorkflows(backend, tenant, cwd) {
19725
19784
  }
19726
19785
  async function hydrateStateWorkspace(config, cwd, backendOverride) {
19727
19786
  const tenant = tenantId(config);
19728
- const configured = Boolean(process.env.CONVEX_URL?.trim()) && Boolean(process.env.KODY_SERVICE_KEY?.trim());
19787
+ const configured = hasStateBackendConfig();
19729
19788
  if (!tenant || !configured) {
19730
19789
  if (process.env.GITHUB_ACTIONS === "true")
19731
- throw new Error("Convex backend is required for runtime workspace documents");
19790
+ throw new Error("Kody backend access is required for runtime workspace documents");
19732
19791
  return;
19733
19792
  }
19734
19793
  const key = `${path43.resolve(cwd)}|${tenant}`;
@@ -24353,12 +24412,12 @@ var BrokerSink = class {
24353
24412
  const be = translateChatEvent(event, this.chatId);
24354
24413
  if (!be) return;
24355
24414
  this.emitToLog(be);
24356
- if (this.tenantId && hasStateBackendConfig()) {
24415
+ if (this.tenantId && hasStateBackendConfig2()) {
24357
24416
  await createStateBackendFromEnv().appendChatEvent(this.tenantId, this.chatId, be);
24358
24417
  }
24359
24418
  }
24360
24419
  };
24361
- function hasStateBackendConfig(env = process.env) {
24420
+ function hasStateBackendConfig2(env = process.env) {
24362
24421
  return Boolean(env.CONVEX_URL?.trim() && env.KODY_SERVICE_KEY?.trim());
24363
24422
  }
24364
24423
  var chatQueues = /* @__PURE__ */ new Map();
@@ -25623,10 +25682,9 @@ async function hydrateDefinitions(options) {
25623
25682
  }
25624
25683
  async function hydrateDefinitionsFromEnv(cwd = process.cwd(), env = process.env) {
25625
25684
  const tenantId2 = env.GITHUB_REPOSITORY?.trim();
25626
- const hasCredentials = Boolean(env.CONVEX_URL?.trim()) && Boolean(env.KODY_SERVICE_KEY?.trim());
25627
- if (!hasCredentials) {
25685
+ if (!hasStateBackendConfig(env)) {
25628
25686
  if (env.GITHUB_ACTIONS === "true") {
25629
- throw new Error("CONVEX_URL and KODY_SERVICE_KEY are required for backend definitions in GitHub Actions");
25687
+ throw new Error("GitHub Actions workflow identity is required for backend definitions");
25630
25688
  }
25631
25689
  return null;
25632
25690
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.409",
3
+ "version": "0.4.410",
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",