@kody-ade/kody-engine 0.4.306 → 0.4.307

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 +406 -337
  2. package/package.json +24 -25
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.306",
18
+ version: "0.4.307",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -549,11 +549,11 @@ function branchApiPath(config, targetPath) {
549
549
  }
550
550
  function ensureStateBranch(config, cwd) {
551
551
  const parsed = parseStateRepo(config);
552
- const cacheKey3 = `${parsed.owner}/${parsed.repo}:${parsed.branch}`;
553
- if (ensuredStateBranches.has(cacheKey3)) return;
552
+ const cacheKey4 = `${parsed.owner}/${parsed.repo}:${parsed.branch}`;
553
+ if (ensuredStateBranches.has(cacheKey4)) return;
554
554
  try {
555
555
  gh(["api", `/repos/${parsed.owner}/${parsed.repo}/git/ref/heads/${parsed.branch}`], { cwd });
556
- ensuredStateBranches.add(cacheKey3);
556
+ ensuredStateBranches.add(cacheKey4);
557
557
  return;
558
558
  } catch (err) {
559
559
  if (!is404(err)) throw err;
@@ -572,7 +572,7 @@ function ensureStateBranch(config, cwd) {
572
572
  } catch (err) {
573
573
  if (!isAlreadyExists(err)) throw err;
574
574
  }
575
- ensuredStateBranches.add(cacheKey3);
575
+ ensuredStateBranches.add(cacheKey4);
576
576
  }
577
577
  function readStateText(config, cwd, filePath) {
578
578
  const targetPath = stateRepoPath(config, filePath);
@@ -8828,12 +8828,12 @@ var init_appendCompanyActivity = __esm({
8828
8828
  }
8829
8829
  });
8830
8830
 
8831
- // src/companyManagerDecision.ts
8832
- function parseCompanyManagerDecisionText(finalText) {
8831
+ // src/agencyArchitectDecision.ts
8832
+ function parseAgencyArchitectDecisionText(finalText) {
8833
8833
  const raw = extractDecisionJson(finalText);
8834
8834
  const parsed = JSON.parse(raw);
8835
8835
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
8836
- throw new Error("company-manager decision must be JSON object");
8836
+ throw new Error("agency-architect decision must be JSON object");
8837
8837
  }
8838
8838
  const input = parsed;
8839
8839
  const actions = Array.isArray(input.actions) ? input.actions.map(parseAction) : [];
@@ -8881,15 +8881,15 @@ function buildAgentLoopState(action) {
8881
8881
  };
8882
8882
  }
8883
8883
  function extractDecisionJson(finalText) {
8884
- const fence = finalText.match(/```(?:kody-company-manager-decision|json)\s*([\s\S]*?)```/i);
8884
+ const fence = finalText.match(/```(?:kody-agency-architect-decision|json)\s*([\s\S]*?)```/i);
8885
8885
  if (fence?.[1]) return fence[1].trim();
8886
- const line = finalText.match(/KODY_COMPANY_MANAGER_DECISION=(\{[\s\S]*\})/);
8886
+ const line = finalText.match(/KODY_AGENCY_ARCHITECT_DECISION=(\{[\s\S]*\})/);
8887
8887
  if (line?.[1]) return line[1].trim();
8888
- throw new Error("missing kody-company-manager-decision JSON");
8888
+ throw new Error("missing kody-agency-architect-decision JSON");
8889
8889
  }
8890
8890
  function parseAction(value) {
8891
8891
  if (!value || typeof value !== "object" || Array.isArray(value)) {
8892
- throw new Error("company-manager action must be object");
8892
+ throw new Error("agency-architect action must be object");
8893
8893
  }
8894
8894
  const input = value;
8895
8895
  const kind = input.kind;
@@ -8898,7 +8898,7 @@ function parseAction(value) {
8898
8898
  if (kind === "setGoalLifecycle") return parseSetGoalLifecycle(input);
8899
8899
  if (kind === "updateIntentPortfolio") return parseUpdateIntentPortfolio(input);
8900
8900
  if (kind === "note") return parseNote(input);
8901
- throw new Error(`unsupported company-manager action kind: ${String(kind)}`);
8901
+ throw new Error(`unsupported agency-architect action kind: ${String(kind)}`);
8902
8902
  }
8903
8903
  function parseCreateManagedGoal(input) {
8904
8904
  const route = Array.isArray(input.route) ? input.route.map(parseRouteStep) : [];
@@ -8994,8 +8994,8 @@ function oneOf(value, allowed, fallback) {
8994
8994
  return typeof value === "string" && allowed.includes(value) ? value : fallback;
8995
8995
  }
8996
8996
  var SLUG_RE;
8997
- var init_companyManagerDecision = __esm({
8998
- "src/companyManagerDecision.ts"() {
8997
+ var init_agencyArchitectDecision = __esm({
8998
+ "src/agencyArchitectDecision.ts"() {
8999
8999
  "use strict";
9000
9000
  init_state2();
9001
9001
  SLUG_RE = /^[a-z][a-z0-9-]{0,63}$/;
@@ -9019,11 +9019,13 @@ function normalizeCompanyIntent(path50, raw) {
9019
9019
  if (!id || !isCompanyIntentId(id)) throw new Error(`${path50}: invalid intent id`);
9020
9020
  const createdAt = stringField3(input.createdAt) || nowIso();
9021
9021
  const updatedAt = stringField3(input.updatedAt) || createdAt;
9022
+ const description = stringField3(input.description);
9022
9023
  return {
9023
9024
  version: 1,
9024
9025
  id,
9025
9026
  status: oneOf2(input.status, ["active", "paused", "archived"], "active"),
9026
9027
  for: stringField3(input.for),
9028
+ ...description ? { description } : {},
9027
9029
  priority: numberField(input.priority, 100),
9028
9030
  posture: oneOf2(
9029
9031
  input.posture,
@@ -9142,8 +9144,8 @@ function normalizeAutomationPolicy(raw) {
9142
9144
  function normalizeManager(raw) {
9143
9145
  return {
9144
9146
  agent: "cto",
9145
- loop: "company-manager-loop",
9146
- capability: "company-manager",
9147
+ loop: "agency-architect-loop",
9148
+ capability: "agency-architect",
9147
9149
  reviewEvery: oneOf2(raw?.reviewEvery, ["1d", "1w"], "1d"),
9148
9150
  ...typeof raw?.lastReviewedAt === "string" ? { lastReviewedAt: raw.lastReviewedAt } : {}
9149
9151
  };
@@ -9159,7 +9161,7 @@ var init_companyIntent = __esm({
9159
9161
  }
9160
9162
  });
9161
9163
 
9162
- // src/scripts/applyCompanyManagerDecision.ts
9164
+ // src/scripts/applyAgencyArchitectDecision.ts
9163
9165
  function applyAction(config, cwd, action) {
9164
9166
  if (action.kind === "createManagedGoal") {
9165
9167
  const existing = fetchGoalState(config, action.id, cwd);
@@ -9228,7 +9230,7 @@ function applied(action, changed, reason, resource) {
9228
9230
  function mergeUnique(left, right) {
9229
9231
  return [.../* @__PURE__ */ new Set([...left, ...right])].sort();
9230
9232
  }
9231
- function logAppliedCompanyManagerActions(config, cwd, appliedActions) {
9233
+ function logAppliedAgencyArchitectActions(config, cwd, appliedActions) {
9232
9234
  const at = nowIso();
9233
9235
  for (const action of appliedActions) {
9234
9236
  if (!action.intentId) continue;
@@ -9243,24 +9245,24 @@ function logAppliedCompanyManagerActions(config, cwd, appliedActions) {
9243
9245
  });
9244
9246
  }
9245
9247
  }
9246
- var applyCompanyManagerDecision;
9247
- var init_applyCompanyManagerDecision = __esm({
9248
- "src/scripts/applyCompanyManagerDecision.ts"() {
9248
+ var applyAgencyArchitectDecision;
9249
+ var init_applyAgencyArchitectDecision = __esm({
9250
+ "src/scripts/applyAgencyArchitectDecision.ts"() {
9249
9251
  "use strict";
9250
- init_companyManagerDecision();
9252
+ init_agencyArchitectDecision();
9251
9253
  init_companyIntent();
9252
9254
  init_stateStore();
9253
9255
  init_state2();
9254
- applyCompanyManagerDecision = async (ctx) => {
9255
- const decision = ctx.data.companyManagerDecision;
9256
+ applyAgencyArchitectDecision = async (ctx) => {
9257
+ const decision = ctx.data.agencyArchitectDecision;
9256
9258
  if (!decision || !Array.isArray(decision.actions)) return;
9257
9259
  if (ctx.output.exitCode !== 0) return;
9258
9260
  const applied2 = [];
9259
9261
  for (const action of decision.actions) {
9260
9262
  applied2.push(applyAction(ctx.config, ctx.cwd, action));
9261
9263
  }
9262
- ctx.data.companyManagerApplied = applied2;
9263
- ctx.data.companyManagerApplySummary = `company-manager applied ${applied2.filter((item) => item.changed).length}/${applied2.length} action(s)`;
9264
+ ctx.data.agencyArchitectApplied = applied2;
9265
+ ctx.data.agencyArchitectApplySummary = `agency-architect applied ${applied2.filter((item) => item.changed).length}/${applied2.length} action(s)`;
9264
9266
  };
9265
9267
  }
9266
9268
  });
@@ -9270,15 +9272,15 @@ var appendCompanyIntentDecision2;
9270
9272
  var init_appendCompanyIntentDecision = __esm({
9271
9273
  "src/scripts/appendCompanyIntentDecision.ts"() {
9272
9274
  "use strict";
9273
- init_applyCompanyManagerDecision();
9275
+ init_applyAgencyArchitectDecision();
9274
9276
  appendCompanyIntentDecision2 = async (ctx) => {
9275
- const applied2 = ctx.data.companyManagerApplied;
9277
+ const applied2 = ctx.data.agencyArchitectApplied;
9276
9278
  if (!applied2 || applied2.length === 0) return;
9277
9279
  try {
9278
- logAppliedCompanyManagerActions(ctx.config, ctx.cwd, applied2);
9280
+ logAppliedAgencyArchitectActions(ctx.config, ctx.cwd, applied2);
9279
9281
  } catch (err) {
9280
9282
  process.stderr.write(
9281
- `[company-manager] failed append intent decision log: ${err instanceof Error ? err.message : String(err)}
9283
+ `[agency-architect] failed append intent decision log: ${err instanceof Error ? err.message : String(err)}
9282
9284
  `
9283
9285
  );
9284
9286
  }
@@ -13471,9 +13473,340 @@ var init_kodyVariables = __esm({
13471
13473
  }
13472
13474
  });
13473
13475
 
13474
- // src/scripts/loadQaContext.ts
13476
+ // src/pool/keys.ts
13477
+ import { hkdfSync } from "crypto";
13478
+ function masterKeyBytes(raw) {
13479
+ const v = raw.trim();
13480
+ if (!v) throw new Error("KODY_MASTER_KEY is empty");
13481
+ if (/^[0-9a-fA-F]+$/.test(v) && v.length === 64) {
13482
+ return Buffer.from(v, "hex");
13483
+ }
13484
+ return Buffer.from(v.replace(/-/g, "+").replace(/_/g, "/"), "base64");
13485
+ }
13486
+ function deriveKey(master, info, length = 32) {
13487
+ return Buffer.from(hkdfSync("sha256", master, Buffer.alloc(0), info, length)).toString("hex");
13488
+ }
13489
+ function derivePoolApiKey(master) {
13490
+ return deriveKey(master, POOL_API_KEY_INFO);
13491
+ }
13492
+ function deriveRunnerApiKey(master) {
13493
+ return deriveKey(master, RUNNER_API_KEY_INFO);
13494
+ }
13495
+ function bearerOk(headerAuth, xApiKey, expected) {
13496
+ const x = (xApiKey ?? "").trim();
13497
+ if (x && timingEqual(x, expected)) return true;
13498
+ const a = (headerAuth ?? "").trim();
13499
+ if (a.toLowerCase().startsWith("bearer ")) {
13500
+ return timingEqual(a.slice(7).trim(), expected);
13501
+ }
13502
+ return false;
13503
+ }
13504
+ function timingEqual(a, b) {
13505
+ if (a.length !== b.length) return false;
13506
+ let diff = 0;
13507
+ for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
13508
+ return diff === 0;
13509
+ }
13510
+ var POOL_API_KEY_INFO, RUNNER_API_KEY_INFO;
13511
+ var init_keys = __esm({
13512
+ "src/pool/keys.ts"() {
13513
+ "use strict";
13514
+ POOL_API_KEY_INFO = "kody-pool-api:v1";
13515
+ RUNNER_API_KEY_INFO = "kody-runner-api:v1";
13516
+ }
13517
+ });
13518
+
13519
+ // src/stateRepoGithub.ts
13475
13520
  import * as fs37 from "fs";
13476
13521
  import * as path35 from "path";
13522
+ function recordValue3(value) {
13523
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
13524
+ }
13525
+ function contentsUrl(owner, repo, filePath) {
13526
+ const encodedPath = filePath.split("/").filter(Boolean).map((part) => encodeURIComponent(part)).join("/");
13527
+ return `${GITHUB_API}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${encodedPath}`;
13528
+ }
13529
+ async function githubContentsFile(opts) {
13530
+ const doFetch = opts.fetchImpl ?? fetch;
13531
+ const res = await doFetch(contentsUrl(opts.owner, opts.repo, opts.path), {
13532
+ headers: {
13533
+ Authorization: `Bearer ${opts.githubToken}`,
13534
+ Accept: "application/vnd.github+json",
13535
+ "X-GitHub-Api-Version": "2022-11-28",
13536
+ "User-Agent": "kody-engine"
13537
+ },
13538
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
13539
+ });
13540
+ if (res.status === 404) return null;
13541
+ if (!res.ok) {
13542
+ throw new Error(
13543
+ `GitHub ${opts.owner}/${opts.repo}:${opts.path}: ${res.status} ${(await res.text().catch(() => "")).slice(0, 160)}`
13544
+ );
13545
+ }
13546
+ return await res.json();
13547
+ }
13548
+ function decodeContentsFile(file, label) {
13549
+ if (file.type !== "file" || file.encoding !== "base64" || typeof file.content !== "string") {
13550
+ throw new Error(`${label} is not a base64 file`);
13551
+ }
13552
+ if (typeof file.sha !== "string") {
13553
+ throw new Error(`${label} response missing sha`);
13554
+ }
13555
+ return {
13556
+ path: label,
13557
+ content: Buffer.from(file.content, "base64").toString("utf-8"),
13558
+ sha: file.sha
13559
+ };
13560
+ }
13561
+ async function loadGithubStateConfig(opts) {
13562
+ const configFile = await githubContentsFile({
13563
+ owner: opts.owner,
13564
+ repo: opts.repo,
13565
+ path: "kody.config.json",
13566
+ githubToken: opts.githubToken,
13567
+ fetchImpl: opts.fetchImpl
13568
+ });
13569
+ let raw = {};
13570
+ if (configFile) {
13571
+ const decoded = decodeContentsFile(configFile, "kody.config.json");
13572
+ try {
13573
+ raw = JSON.parse(decoded.content);
13574
+ } catch (err) {
13575
+ throw new Error(`kody.config.json is invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
13576
+ }
13577
+ }
13578
+ const githubRaw = recordValue3(raw.github) ?? {};
13579
+ const github = {
13580
+ owner: typeof githubRaw.owner === "string" && githubRaw.owner.trim() ? githubRaw.owner.trim() : opts.owner,
13581
+ repo: typeof githubRaw.repo === "string" && githubRaw.repo.trim() ? githubRaw.repo.trim() : opts.repo
13582
+ };
13583
+ const nestedState = recordValue3(raw.state) ?? {};
13584
+ const repoRaw = typeof raw.stateRepo === "string" ? raw.stateRepo : nestedState.repo;
13585
+ const pathRaw = typeof raw.statePath === "string" ? raw.statePath : nestedState.path;
13586
+ const stateRepo = typeof repoRaw === "string" && repoRaw.trim().length > 0 ? repoRaw.trim() : `https://github.com/${github.owner}/kody-state`;
13587
+ parseStateRepoSlug(stateRepo);
13588
+ const statePath = typeof pathRaw === "string" && pathRaw.trim().length > 0 ? pathRaw.trim() : github.repo;
13589
+ return {
13590
+ github,
13591
+ state: {
13592
+ repo: stateRepo,
13593
+ path: normalizeStatePath(statePath)
13594
+ }
13595
+ };
13596
+ }
13597
+ async function readGithubStateText(opts) {
13598
+ const config = await loadGithubStateConfig(opts);
13599
+ return readGithubStateTextWithConfig({
13600
+ config,
13601
+ filePath: opts.filePath,
13602
+ githubToken: opts.githubToken,
13603
+ fetchImpl: opts.fetchImpl
13604
+ });
13605
+ }
13606
+ async function readGithubStateTextWithConfig(opts) {
13607
+ const target = stateRepoPath(opts.config, opts.filePath);
13608
+ const parsed = parseStateRepo(opts.config);
13609
+ const file = await githubContentsFile({
13610
+ owner: parsed.owner,
13611
+ repo: parsed.repo,
13612
+ path: target,
13613
+ githubToken: opts.githubToken,
13614
+ fetchImpl: opts.fetchImpl
13615
+ });
13616
+ return file ? decodeContentsFile(file, target) : null;
13617
+ }
13618
+ async function writeGithubStateTextWithConfig(opts) {
13619
+ const target = stateRepoPath(opts.config, opts.filePath);
13620
+ const parsed = parseStateRepo(opts.config);
13621
+ const payload = {
13622
+ message: opts.message,
13623
+ content: Buffer.from(opts.content, "utf-8").toString("base64")
13624
+ };
13625
+ if (opts.sha) payload.sha = opts.sha;
13626
+ const doFetch = opts.fetchImpl ?? fetch;
13627
+ const res = await doFetch(contentsUrl(parsed.owner, parsed.repo, target), {
13628
+ method: "PUT",
13629
+ headers: {
13630
+ Authorization: `Bearer ${opts.githubToken}`,
13631
+ Accept: "application/vnd.github+json",
13632
+ "Content-Type": "application/json",
13633
+ "X-GitHub-Api-Version": "2022-11-28",
13634
+ "User-Agent": "kody-engine"
13635
+ },
13636
+ body: JSON.stringify(payload),
13637
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
13638
+ });
13639
+ if (!res.ok) {
13640
+ throw new Error(
13641
+ `GitHub write ${parsed.owner}/${parsed.repo}:${target}: ${res.status} ${(await res.text().catch(() => "")).slice(0, 160)}`
13642
+ );
13643
+ }
13644
+ }
13645
+ function jsonlLines(text) {
13646
+ return text.split("\n").filter((line) => line.length > 0);
13647
+ }
13648
+ function renderJsonl(lines) {
13649
+ return lines.length > 0 ? `${lines.join("\n")}
13650
+ ` : "";
13651
+ }
13652
+ function mergeJsonl(localText, remoteText) {
13653
+ const remoteLines = jsonlLines(remoteText);
13654
+ const seen = new Set(remoteLines);
13655
+ const localOnly = jsonlLines(localText).filter((line) => !seen.has(line));
13656
+ return renderJsonl([...remoteLines, ...localOnly]);
13657
+ }
13658
+ async function syncJsonlFileFromGithubState(opts) {
13659
+ const remote = await readGithubStateTextWithConfig(opts);
13660
+ if (!remote) return;
13661
+ const local = fs37.existsSync(opts.localPath) ? fs37.readFileSync(opts.localPath, "utf-8") : "";
13662
+ const next = mergeJsonl(local, remote.content);
13663
+ if (next === local) return;
13664
+ fs37.mkdirSync(path35.dirname(opts.localPath), { recursive: true });
13665
+ fs37.writeFileSync(opts.localPath, next);
13666
+ }
13667
+ async function persistJsonlFileToGithubState(opts) {
13668
+ if (!fs37.existsSync(opts.localPath)) return;
13669
+ const localText = fs37.readFileSync(opts.localPath, "utf-8");
13670
+ for (let attempt = 1; attempt <= 3; attempt += 1) {
13671
+ const remote = await readGithubStateTextWithConfig(opts);
13672
+ const body = mergeJsonl(localText, remote?.content ?? "");
13673
+ try {
13674
+ await writeGithubStateTextWithConfig({
13675
+ config: opts.config,
13676
+ filePath: opts.filePath,
13677
+ content: body,
13678
+ message: opts.message,
13679
+ githubToken: opts.githubToken,
13680
+ sha: remote?.sha,
13681
+ fetchImpl: opts.fetchImpl
13682
+ });
13683
+ return;
13684
+ } catch (err) {
13685
+ const msg = err instanceof Error ? err.message : String(err);
13686
+ const conflict = /409|422|does not match|is at|but expected/i.test(msg);
13687
+ if (!conflict || attempt === 3) throw err;
13688
+ }
13689
+ }
13690
+ }
13691
+ var GITHUB_API, REQ_TIMEOUT_MS;
13692
+ var init_stateRepoGithub = __esm({
13693
+ "src/stateRepoGithub.ts"() {
13694
+ "use strict";
13695
+ init_stateRepo();
13696
+ GITHUB_API = "https://api.github.com";
13697
+ REQ_TIMEOUT_MS = 3e4;
13698
+ }
13699
+ });
13700
+
13701
+ // src/stateRepoVault.ts
13702
+ import { createDecipheriv, createHash as createHash3 } from "crypto";
13703
+ function cacheKey2(owner, repo, masterKey) {
13704
+ const keyHash = createHash3("sha256").update(masterKey).digest("hex").slice(0, 16);
13705
+ return `${owner}/${repo}:${keyHash}`.toLowerCase();
13706
+ }
13707
+ function decryptVault(payload, masterKey) {
13708
+ const parts = payload.split(":");
13709
+ if (parts.length !== 4 || parts[0] !== "v1") {
13710
+ throw new Error("invalid vault payload format");
13711
+ }
13712
+ const [, ivB64, ctB64, tagB64] = parts;
13713
+ const iv = Buffer.from(ivB64, "base64");
13714
+ const ct = Buffer.from(ctB64, "base64");
13715
+ const tag = Buffer.from(tagB64, "base64");
13716
+ const decipher = createDecipheriv("aes-256-gcm", masterKey, iv);
13717
+ decipher.setAuthTag(tag);
13718
+ return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
13719
+ }
13720
+ async function readVaultSecrets(opts) {
13721
+ const key = cacheKey2(opts.owner, opts.repo, opts.masterKey);
13722
+ const hit = cache.get(key);
13723
+ if (hit && hit.expiresAt > Date.now()) return hit.secrets;
13724
+ const file = await readGithubStateText({
13725
+ owner: opts.owner,
13726
+ repo: opts.repo,
13727
+ filePath: VAULT_PATH,
13728
+ githubToken: opts.githubToken,
13729
+ fetchImpl: opts.fetchImpl
13730
+ });
13731
+ if (!file) {
13732
+ cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
13733
+ return {};
13734
+ }
13735
+ const ciphertext = file.content.trim();
13736
+ const doc = JSON.parse(decryptVault(ciphertext, opts.masterKey));
13737
+ const flat = {};
13738
+ for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
13739
+ if (entry && typeof entry.value === "string") flat[name] = entry.value;
13740
+ }
13741
+ cache.set(key, { secrets: flat, expiresAt: Date.now() + CACHE_TTL_MS });
13742
+ return flat;
13743
+ }
13744
+ async function readRepoSecret(opts) {
13745
+ const secrets = await readVaultSecrets(opts);
13746
+ const v = secrets[opts.name];
13747
+ return v?.trim() ? v : null;
13748
+ }
13749
+ async function readRepoSecrets(opts) {
13750
+ return readVaultSecrets(opts);
13751
+ }
13752
+ var VAULT_PATH, CACHE_TTL_MS, cache;
13753
+ var init_stateRepoVault = __esm({
13754
+ "src/stateRepoVault.ts"() {
13755
+ "use strict";
13756
+ init_stateRepoGithub();
13757
+ VAULT_PATH = "secrets.enc";
13758
+ CACHE_TTL_MS = 6e4;
13759
+ cache = /* @__PURE__ */ new Map();
13760
+ }
13761
+ });
13762
+
13763
+ // src/scripts/runtimeSecrets.ts
13764
+ function tokenFromEnv(env) {
13765
+ return (env.KODY_TOKEN ?? env.GH_TOKEN ?? env.GITHUB_TOKEN ?? env.GH_PAT ?? "").trim();
13766
+ }
13767
+ function envSecret(name, env) {
13768
+ const value = env[name]?.trim() ? env[name] : "";
13769
+ return value ? { value, source: "env" } : { value: "", source: "missing" };
13770
+ }
13771
+ async function resolveRuntimeSecret(name, ctx, opts = {}) {
13772
+ const env = opts.env ?? process.env;
13773
+ const masterRaw = env.KODY_MASTER_KEY?.trim() ?? "";
13774
+ const githubToken2 = tokenFromEnv(env);
13775
+ if (!masterRaw || !githubToken2) return envSecret(name, env);
13776
+ try {
13777
+ const masterKey = masterKeyBytes(masterRaw);
13778
+ if (masterKey.length !== 32) {
13779
+ throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
13780
+ }
13781
+ const value = await readRepoSecret({
13782
+ owner: ctx.config.github.owner,
13783
+ repo: ctx.config.github.repo,
13784
+ name,
13785
+ githubToken: githubToken2,
13786
+ masterKey,
13787
+ fetchImpl: opts.fetchImpl
13788
+ });
13789
+ if (value) return { value, source: "vault" };
13790
+ } catch (err) {
13791
+ const fallback = envSecret(name, env);
13792
+ return {
13793
+ ...fallback,
13794
+ warning: `vault read failed for ${name}: ${err instanceof Error ? err.message : String(err)}`
13795
+ };
13796
+ }
13797
+ return envSecret(name, env);
13798
+ }
13799
+ var init_runtimeSecrets = __esm({
13800
+ "src/scripts/runtimeSecrets.ts"() {
13801
+ "use strict";
13802
+ init_keys();
13803
+ init_stateRepoVault();
13804
+ }
13805
+ });
13806
+
13807
+ // src/scripts/loadQaContext.ts
13808
+ import * as fs38 from "fs";
13809
+ import * as path36 from "path";
13477
13810
  function parseSlugList(value) {
13478
13811
  const inner = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
13479
13812
  return inner.split(",").map(
@@ -13502,18 +13835,18 @@ function readProfileAgents(raw) {
13502
13835
  return { agent: agent ?? legacy ?? ["kody"], body };
13503
13836
  }
13504
13837
  function readProfile(cwd) {
13505
- const dir = path35.join(cwd, CONTEXT_DIR_REL_PATH);
13506
- if (!fs37.existsSync(dir)) return "";
13838
+ const dir = path36.join(cwd, CONTEXT_DIR_REL_PATH);
13839
+ if (!fs38.existsSync(dir)) return "";
13507
13840
  let entries;
13508
13841
  try {
13509
- entries = fs37.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
13842
+ entries = fs38.readdirSync(dir).filter((f) => f.endsWith(".md")).sort();
13510
13843
  } catch {
13511
13844
  return "";
13512
13845
  }
13513
13846
  const blocks = [];
13514
13847
  for (const file of entries) {
13515
13848
  try {
13516
- const raw = fs37.readFileSync(path35.join(dir, file), "utf-8");
13849
+ const raw = fs38.readFileSync(path36.join(dir, file), "utf-8");
13517
13850
  const { agent, body } = readProfileAgents(raw);
13518
13851
  if (!agent.includes(QA_AGENT) && !agent.includes(ALL_AGENTS)) continue;
13519
13852
  blocks.push(`## ${file}
@@ -13541,6 +13874,7 @@ var init_loadQaContext = __esm({
13541
13874
  "src/scripts/loadQaContext.ts"() {
13542
13875
  "use strict";
13543
13876
  init_kodyVariables();
13877
+ init_runtimeSecrets();
13544
13878
  CONTEXT_DIR_REL_PATH = ".kody/context";
13545
13879
  QA_AGENT = "qa-engineer";
13546
13880
  ALL_AGENTS = "*";
@@ -13549,18 +13883,20 @@ var init_loadQaContext = __esm({
13549
13883
  loadQaContext = async (ctx) => {
13550
13884
  const vars = readKodyVariables(ctx.cwd);
13551
13885
  const login = vars.LOGIN_USER ?? "";
13552
- const password = process.env.LOGIN_PASSWORD ?? "";
13886
+ const password = await resolveRuntimeSecret("LOGIN_PASSWORD", ctx);
13553
13887
  const authProfile = ctx.args.authProfile;
13554
13888
  ctx.data.qaLogin = login;
13889
+ ctx.data.qaPasswordSource = password.source;
13890
+ if (password.warning) ctx.data.qaPasswordWarning = password.warning;
13555
13891
  ctx.data.qaProfile = readProfile(ctx.cwd);
13556
- ctx.data.qaAuthBlock = composeAuthBlock(authProfile, login, password);
13892
+ ctx.data.qaAuthBlock = composeAuthBlock(authProfile, login, password.value);
13557
13893
  };
13558
13894
  }
13559
13895
  });
13560
13896
 
13561
13897
  // src/taskContext.ts
13562
- import * as fs38 from "fs";
13563
- import * as path36 from "path";
13898
+ import * as fs39 from "fs";
13899
+ import * as path37 from "path";
13564
13900
  function buildTaskContext(args) {
13565
13901
  return {
13566
13902
  schemaVersion: TASK_CONTEXT_SCHEMA_VERSION,
@@ -13576,9 +13912,9 @@ function buildTaskContext(args) {
13576
13912
  function persistTaskContext(cwd, ctx) {
13577
13913
  try {
13578
13914
  const dir = runtimeStatePath(cwd, "agent-runs", ctx.runId);
13579
- fs38.mkdirSync(dir, { recursive: true });
13580
- const file = path36.join(dir, "task-context.json");
13581
- fs38.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
13915
+ fs39.mkdirSync(dir, { recursive: true });
13916
+ const file = path37.join(dir, "task-context.json");
13917
+ fs39.writeFileSync(file, `${JSON.stringify(ctx, null, 2)}
13582
13918
  `);
13583
13919
  return file;
13584
13920
  } catch (err) {
@@ -14349,32 +14685,32 @@ var init_parseAgentResult = __esm({
14349
14685
  }
14350
14686
  });
14351
14687
 
14352
- // src/scripts/parseCompanyManagerDecision.ts
14688
+ // src/scripts/parseAgencyArchitectDecision.ts
14353
14689
  function makeAction3(type, payload) {
14354
14690
  return { type, payload, timestamp: (/* @__PURE__ */ new Date()).toISOString() };
14355
14691
  }
14356
- var parseCompanyManagerDecision;
14357
- var init_parseCompanyManagerDecision = __esm({
14358
- "src/scripts/parseCompanyManagerDecision.ts"() {
14692
+ var parseAgencyArchitectDecision;
14693
+ var init_parseAgencyArchitectDecision = __esm({
14694
+ "src/scripts/parseAgencyArchitectDecision.ts"() {
14359
14695
  "use strict";
14360
- init_companyManagerDecision();
14361
- parseCompanyManagerDecision = async (ctx, _profile, agentResult) => {
14696
+ init_agencyArchitectDecision();
14697
+ parseAgencyArchitectDecision = async (ctx, _profile, agentResult) => {
14362
14698
  if (!agentResult) {
14363
- ctx.data.companyManagerDecision = { summary: "", actions: [] };
14364
- ctx.data.action = makeAction3("COMPANY_MANAGER_NOT_RUN", { reason: "no agent result" });
14699
+ ctx.data.agencyArchitectDecision = { summary: "", actions: [] };
14700
+ ctx.data.action = makeAction3("AGENCY_ARCHITECT_NOT_RUN", { reason: "no agent result" });
14365
14701
  return;
14366
14702
  }
14367
14703
  try {
14368
- const decision = parseCompanyManagerDecisionText(agentResult.finalText);
14369
- ctx.data.companyManagerDecision = decision;
14370
- ctx.data.action = makeAction3("COMPANY_MANAGER_DECIDED", {
14704
+ const decision = parseAgencyArchitectDecisionText(agentResult.finalText);
14705
+ ctx.data.agencyArchitectDecision = decision;
14706
+ ctx.data.action = makeAction3("AGENCY_ARCHITECT_DECIDED", {
14371
14707
  summary: decision.summary,
14372
14708
  actionCount: decision.actions.length
14373
14709
  });
14374
14710
  } catch (err) {
14375
14711
  const reason = err instanceof Error ? err.message : String(err);
14376
- ctx.data.companyManagerDecisionError = reason;
14377
- ctx.data.action = makeAction3("COMPANY_MANAGER_FAILED", { reason });
14712
+ ctx.data.agencyArchitectDecisionError = reason;
14713
+ ctx.data.action = makeAction3("AGENCY_ARCHITECT_FAILED", { reason });
14378
14714
  ctx.output.exitCode = 1;
14379
14715
  ctx.output.reason = reason;
14380
14716
  }
@@ -15873,192 +16209,10 @@ var init_runFlow = __esm({
15873
16209
  }
15874
16210
  });
15875
16211
 
15876
- // src/stateRepoGithub.ts
15877
- import * as fs39 from "fs";
15878
- import * as path37 from "path";
15879
- function recordValue3(value) {
15880
- return value && typeof value === "object" && !Array.isArray(value) ? value : null;
15881
- }
15882
- function contentsUrl(owner, repo, filePath) {
15883
- const encodedPath = filePath.split("/").filter(Boolean).map((part) => encodeURIComponent(part)).join("/");
15884
- return `${GITHUB_API}/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}/contents/${encodedPath}`;
15885
- }
15886
- async function githubContentsFile(opts) {
15887
- const doFetch = opts.fetchImpl ?? fetch;
15888
- const res = await doFetch(contentsUrl(opts.owner, opts.repo, opts.path), {
15889
- headers: {
15890
- Authorization: `Bearer ${opts.githubToken}`,
15891
- Accept: "application/vnd.github+json",
15892
- "X-GitHub-Api-Version": "2022-11-28",
15893
- "User-Agent": "kody-engine"
15894
- },
15895
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
15896
- });
15897
- if (res.status === 404) return null;
15898
- if (!res.ok) {
15899
- throw new Error(
15900
- `GitHub ${opts.owner}/${opts.repo}:${opts.path}: ${res.status} ${(await res.text().catch(() => "")).slice(0, 160)}`
15901
- );
15902
- }
15903
- return await res.json();
15904
- }
15905
- function decodeContentsFile(file, label) {
15906
- if (file.type !== "file" || file.encoding !== "base64" || typeof file.content !== "string") {
15907
- throw new Error(`${label} is not a base64 file`);
15908
- }
15909
- if (typeof file.sha !== "string") {
15910
- throw new Error(`${label} response missing sha`);
15911
- }
15912
- return {
15913
- path: label,
15914
- content: Buffer.from(file.content, "base64").toString("utf-8"),
15915
- sha: file.sha
15916
- };
15917
- }
15918
- async function loadGithubStateConfig(opts) {
15919
- const configFile = await githubContentsFile({
15920
- owner: opts.owner,
15921
- repo: opts.repo,
15922
- path: "kody.config.json",
15923
- githubToken: opts.githubToken,
15924
- fetchImpl: opts.fetchImpl
15925
- });
15926
- let raw = {};
15927
- if (configFile) {
15928
- const decoded = decodeContentsFile(configFile, "kody.config.json");
15929
- try {
15930
- raw = JSON.parse(decoded.content);
15931
- } catch (err) {
15932
- throw new Error(`kody.config.json is invalid JSON: ${err instanceof Error ? err.message : String(err)}`);
15933
- }
15934
- }
15935
- const githubRaw = recordValue3(raw.github) ?? {};
15936
- const github = {
15937
- owner: typeof githubRaw.owner === "string" && githubRaw.owner.trim() ? githubRaw.owner.trim() : opts.owner,
15938
- repo: typeof githubRaw.repo === "string" && githubRaw.repo.trim() ? githubRaw.repo.trim() : opts.repo
15939
- };
15940
- const nestedState = recordValue3(raw.state) ?? {};
15941
- const repoRaw = typeof raw.stateRepo === "string" ? raw.stateRepo : nestedState.repo;
15942
- const pathRaw = typeof raw.statePath === "string" ? raw.statePath : nestedState.path;
15943
- const stateRepo = typeof repoRaw === "string" && repoRaw.trim().length > 0 ? repoRaw.trim() : `https://github.com/${github.owner}/kody-state`;
15944
- parseStateRepoSlug(stateRepo);
15945
- const statePath = typeof pathRaw === "string" && pathRaw.trim().length > 0 ? pathRaw.trim() : github.repo;
15946
- return {
15947
- github,
15948
- state: {
15949
- repo: stateRepo,
15950
- path: normalizeStatePath(statePath)
15951
- }
15952
- };
15953
- }
15954
- async function readGithubStateText(opts) {
15955
- const config = await loadGithubStateConfig(opts);
15956
- return readGithubStateTextWithConfig({
15957
- config,
15958
- filePath: opts.filePath,
15959
- githubToken: opts.githubToken,
15960
- fetchImpl: opts.fetchImpl
15961
- });
15962
- }
15963
- async function readGithubStateTextWithConfig(opts) {
15964
- const target = stateRepoPath(opts.config, opts.filePath);
15965
- const parsed = parseStateRepo(opts.config);
15966
- const file = await githubContentsFile({
15967
- owner: parsed.owner,
15968
- repo: parsed.repo,
15969
- path: target,
15970
- githubToken: opts.githubToken,
15971
- fetchImpl: opts.fetchImpl
15972
- });
15973
- return file ? decodeContentsFile(file, target) : null;
15974
- }
15975
- async function writeGithubStateTextWithConfig(opts) {
15976
- const target = stateRepoPath(opts.config, opts.filePath);
15977
- const parsed = parseStateRepo(opts.config);
15978
- const payload = {
15979
- message: opts.message,
15980
- content: Buffer.from(opts.content, "utf-8").toString("base64")
15981
- };
15982
- if (opts.sha) payload.sha = opts.sha;
15983
- const doFetch = opts.fetchImpl ?? fetch;
15984
- const res = await doFetch(contentsUrl(parsed.owner, parsed.repo, target), {
15985
- method: "PUT",
15986
- headers: {
15987
- Authorization: `Bearer ${opts.githubToken}`,
15988
- Accept: "application/vnd.github+json",
15989
- "Content-Type": "application/json",
15990
- "X-GitHub-Api-Version": "2022-11-28",
15991
- "User-Agent": "kody-engine"
15992
- },
15993
- body: JSON.stringify(payload),
15994
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
15995
- });
15996
- if (!res.ok) {
15997
- throw new Error(
15998
- `GitHub write ${parsed.owner}/${parsed.repo}:${target}: ${res.status} ${(await res.text().catch(() => "")).slice(0, 160)}`
15999
- );
16000
- }
16001
- }
16002
- function jsonlLines(text) {
16003
- return text.split("\n").filter((line) => line.length > 0);
16004
- }
16005
- function renderJsonl(lines) {
16006
- return lines.length > 0 ? `${lines.join("\n")}
16007
- ` : "";
16008
- }
16009
- function mergeJsonl(localText, remoteText) {
16010
- const remoteLines = jsonlLines(remoteText);
16011
- const seen = new Set(remoteLines);
16012
- const localOnly = jsonlLines(localText).filter((line) => !seen.has(line));
16013
- return renderJsonl([...remoteLines, ...localOnly]);
16014
- }
16015
- async function syncJsonlFileFromGithubState(opts) {
16016
- const remote = await readGithubStateTextWithConfig(opts);
16017
- if (!remote) return;
16018
- const local = fs39.existsSync(opts.localPath) ? fs39.readFileSync(opts.localPath, "utf-8") : "";
16019
- const next = mergeJsonl(local, remote.content);
16020
- if (next === local) return;
16021
- fs39.mkdirSync(path37.dirname(opts.localPath), { recursive: true });
16022
- fs39.writeFileSync(opts.localPath, next);
16023
- }
16024
- async function persistJsonlFileToGithubState(opts) {
16025
- if (!fs39.existsSync(opts.localPath)) return;
16026
- const localText = fs39.readFileSync(opts.localPath, "utf-8");
16027
- for (let attempt = 1; attempt <= 3; attempt += 1) {
16028
- const remote = await readGithubStateTextWithConfig(opts);
16029
- const body = mergeJsonl(localText, remote?.content ?? "");
16030
- try {
16031
- await writeGithubStateTextWithConfig({
16032
- config: opts.config,
16033
- filePath: opts.filePath,
16034
- content: body,
16035
- message: opts.message,
16036
- githubToken: opts.githubToken,
16037
- sha: remote?.sha,
16038
- fetchImpl: opts.fetchImpl
16039
- });
16040
- return;
16041
- } catch (err) {
16042
- const msg = err instanceof Error ? err.message : String(err);
16043
- const conflict = /409|422|does not match|is at|but expected/i.test(msg);
16044
- if (!conflict || attempt === 3) throw err;
16045
- }
16046
- }
16047
- }
16048
- var GITHUB_API, REQ_TIMEOUT_MS;
16049
- var init_stateRepoGithub = __esm({
16050
- "src/stateRepoGithub.ts"() {
16051
- "use strict";
16052
- init_stateRepo();
16053
- GITHUB_API = "https://api.github.com";
16054
- REQ_TIMEOUT_MS = 3e4;
16055
- }
16056
- });
16057
-
16058
16212
  // src/scripts/previewBuildHelpers.ts
16059
- import { createDecipheriv, createHash as createHash3, hkdfSync } from "crypto";
16213
+ import { createDecipheriv as createDecipheriv2, createHash as createHash4, hkdfSync as hkdfSync2 } from "crypto";
16060
16214
  function shortHash(s) {
16061
- return createHash3("sha256").update(s).digest("hex").slice(0, 6);
16215
+ return createHash4("sha256").update(s).digest("hex").slice(0, 6);
16062
16216
  }
16063
16217
  function previewAppName(repo, pr) {
16064
16218
  const [owner, name] = repo.split("/");
@@ -16087,7 +16241,7 @@ function decryptVaultPayload(payload, keyRaw) {
16087
16241
  const iv = Buffer.from(ivB64, "base64");
16088
16242
  const ct = Buffer.from(ctB64, "base64");
16089
16243
  const tag = Buffer.from(tagB64, "base64");
16090
- const decipher = createDecipheriv("aes-256-gcm", key, iv);
16244
+ const decipher = createDecipheriv2("aes-256-gcm", key, iv);
16091
16245
  decipher.setAuthTag(tag);
16092
16246
  return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
16093
16247
  }
@@ -16100,7 +16254,7 @@ function derivePreviewVerifyKey(masterKeyRaw) {
16100
16254
  if (masterKey.length !== 32) {
16101
16255
  throw new Error("KODY_MASTER_KEY must decode to 32 bytes");
16102
16256
  }
16103
- return Buffer.from(hkdfSync("sha256", masterKey, Buffer.alloc(0), PREVIEW_KEY_INFO, 32)).toString("hex");
16257
+ return Buffer.from(hkdfSync2("sha256", masterKey, Buffer.alloc(0), PREVIEW_KEY_INFO, 32)).toString("hex");
16104
16258
  }
16105
16259
  function previewRuntimeEnv(args) {
16106
16260
  return {
@@ -16131,7 +16285,7 @@ function formatPreviewComment(args) {
16131
16285
  ].join("\n");
16132
16286
  }
16133
16287
  function defaultImageTag(repo, ref) {
16134
- return createHash3("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
16288
+ return createHash4("sha256").update(`${repo}@${ref}`).digest("hex").slice(0, 12);
16135
16289
  }
16136
16290
  var NEVER_PASS_TO_BUILD, PREVIEW_KEY_INFO;
16137
16291
  var init_previewBuildHelpers = __esm({
@@ -17746,7 +17900,7 @@ var init_scripts = __esm({
17746
17900
  init_appendCompanyActivity();
17747
17901
  init_appendCompanyIntentDecision();
17748
17902
  init_applyCapabilityReports();
17749
- init_applyCompanyManagerDecision();
17903
+ init_applyAgencyArchitectDecision();
17750
17904
  init_buildSyntheticPlugin();
17751
17905
  init_checkCoverageWithRetry();
17752
17906
  init_classifyByLabel();
@@ -17793,7 +17947,7 @@ var init_scripts = __esm({
17793
17947
  init_openAgentFactoryStatePr();
17794
17948
  init_openQaIssue();
17795
17949
  init_parseAgentResult();
17796
- init_parseCompanyManagerDecision();
17950
+ init_parseAgencyArchitectDecision();
17797
17951
  init_parseIssueStateFromAgentResult();
17798
17952
  init_parseJobStateFromAgentResult();
17799
17953
  init_parseReproOutput();
@@ -17888,7 +18042,7 @@ var init_scripts = __esm({
17888
18042
  };
17889
18043
  postflightScripts = {
17890
18044
  parseAgentResult: parseAgentResult2,
17891
- parseCompanyManagerDecision,
18045
+ parseAgencyArchitectDecision,
17892
18046
  parseIssueStateFromAgentResult,
17893
18047
  parseJobStateFromAgentResult,
17894
18048
  parseReproOutput,
@@ -17896,7 +18050,7 @@ var init_scripts = __esm({
17896
18050
  writeJobStateFile,
17897
18051
  appendCompanyActivity,
17898
18052
  appendCompanyIntentDecision: appendCompanyIntentDecision2,
17899
- applyCompanyManagerDecision,
18053
+ applyAgencyArchitectDecision,
17900
18054
  requireFeedbackActions,
17901
18055
  requirePlanDeviations,
17902
18056
  verify,
@@ -17987,7 +18141,7 @@ function hydrateStateWorkspace(config, cwd) {
17987
18141
  hydratedWorkspaces.add(hydrateKey);
17988
18142
  }
17989
18143
  function fetchStateSnapshot(parsed) {
17990
- const cacheDir = path41.join(cacheRoot2(), cacheKey2(parsed));
18144
+ const cacheDir = path41.join(cacheRoot2(), cacheKey3(parsed));
17991
18145
  const url = `https://github.com/${parsed.owner}/${parsed.repo}.git`;
17992
18146
  try {
17993
18147
  fs43.mkdirSync(path41.dirname(cacheDir), { recursive: true });
@@ -18012,7 +18166,7 @@ function fetchStateSnapshot(parsed) {
18012
18166
  function cacheRoot2() {
18013
18167
  return process.env[CACHE_ENV2]?.trim() || path41.join(os7.homedir(), ".cache", "kody", "state-repo");
18014
18168
  }
18015
- function cacheKey2(parsed) {
18169
+ function cacheKey3(parsed) {
18016
18170
  return crypto3.createHash("sha256").update(`${parsed.owner}/${parsed.repo}#${parsed.branch}#${parsed.basePath}`).digest("hex").slice(0, 24);
18017
18171
  }
18018
18172
  function runGit3(args) {
@@ -23130,42 +23284,8 @@ async function runCapabilityFallbackTick(deps) {
23130
23284
  return { ran: true, claimed };
23131
23285
  }
23132
23286
 
23133
- // src/pool/keys.ts
23134
- import { hkdfSync as hkdfSync2 } from "crypto";
23135
- var POOL_API_KEY_INFO = "kody-pool-api:v1";
23136
- var RUNNER_API_KEY_INFO = "kody-runner-api:v1";
23137
- function masterKeyBytes(raw) {
23138
- const v = raw.trim();
23139
- if (!v) throw new Error("KODY_MASTER_KEY is empty");
23140
- if (/^[0-9a-fA-F]+$/.test(v) && v.length === 64) {
23141
- return Buffer.from(v, "hex");
23142
- }
23143
- return Buffer.from(v.replace(/-/g, "+").replace(/_/g, "/"), "base64");
23144
- }
23145
- function deriveKey(master, info, length = 32) {
23146
- return Buffer.from(hkdfSync2("sha256", master, Buffer.alloc(0), info, length)).toString("hex");
23147
- }
23148
- function derivePoolApiKey(master) {
23149
- return deriveKey(master, POOL_API_KEY_INFO);
23150
- }
23151
- function deriveRunnerApiKey(master) {
23152
- return deriveKey(master, RUNNER_API_KEY_INFO);
23153
- }
23154
- function bearerOk(headerAuth, xApiKey, expected) {
23155
- const x = (xApiKey ?? "").trim();
23156
- if (x && timingEqual(x, expected)) return true;
23157
- const a = (headerAuth ?? "").trim();
23158
- if (a.toLowerCase().startsWith("bearer ")) {
23159
- return timingEqual(a.slice(7).trim(), expected);
23160
- }
23161
- return false;
23162
- }
23163
- function timingEqual(a, b) {
23164
- if (a.length !== b.length) return false;
23165
- let diff = 0;
23166
- for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
23167
- return diff === 0;
23168
- }
23287
+ // src/servers/pool-serve.ts
23288
+ init_keys();
23169
23289
 
23170
23290
  // src/pool/fly.ts
23171
23291
  var FLY_API_BASE = "https://api.machines.dev/v1";
@@ -23530,59 +23650,8 @@ function isSuspendedWithIp(m) {
23530
23650
  return (m.state === "suspended" || m.state === "suspending") && !!m.private_ip;
23531
23651
  }
23532
23652
 
23533
- // src/pool/vault.ts
23534
- init_stateRepoGithub();
23535
- import { createDecipheriv as createDecipheriv2 } from "crypto";
23536
- var VAULT_PATH = "secrets.enc";
23537
- var CACHE_TTL_MS = 6e4;
23538
- var cache = /* @__PURE__ */ new Map();
23539
- function decryptVault(payload, masterKey) {
23540
- const parts = payload.split(":");
23541
- if (parts.length !== 4 || parts[0] !== "v1") {
23542
- throw new Error("invalid vault payload format");
23543
- }
23544
- const [, ivB64, ctB64, tagB64] = parts;
23545
- const iv = Buffer.from(ivB64, "base64");
23546
- const ct = Buffer.from(ctB64, "base64");
23547
- const tag = Buffer.from(tagB64, "base64");
23548
- const decipher = createDecipheriv2("aes-256-gcm", masterKey, iv);
23549
- decipher.setAuthTag(tag);
23550
- return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
23551
- }
23552
- async function readVaultSecrets(opts) {
23553
- const key = `${opts.owner}/${opts.repo}`.toLowerCase();
23554
- const hit = cache.get(key);
23555
- if (hit && hit.expiresAt > Date.now()) return hit.secrets;
23556
- const file = await readGithubStateText({
23557
- owner: opts.owner,
23558
- repo: opts.repo,
23559
- filePath: VAULT_PATH,
23560
- githubToken: opts.githubToken,
23561
- fetchImpl: opts.fetchImpl
23562
- });
23563
- if (!file) {
23564
- cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
23565
- return {};
23566
- }
23567
- const ciphertext = file.content.trim();
23568
- const doc = JSON.parse(decryptVault(ciphertext, opts.masterKey));
23569
- const flat = {};
23570
- for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
23571
- if (entry && typeof entry.value === "string") flat[name] = entry.value;
23572
- }
23573
- cache.set(key, { secrets: flat, expiresAt: Date.now() + CACHE_TTL_MS });
23574
- return flat;
23575
- }
23576
- async function readRepoSecret(opts) {
23577
- const secrets = await readVaultSecrets(opts);
23578
- const v = secrets[opts.name];
23579
- return v?.trim() ? v : null;
23580
- }
23581
- async function readRepoSecrets(opts) {
23582
- return readVaultSecrets(opts);
23583
- }
23584
-
23585
23653
  // src/pool/registry.ts
23654
+ init_stateRepoVault();
23586
23655
  var POOL_MIN_VAULT_KEY = "POOL_MIN";
23587
23656
  var POOL_MIN_MAX = 10;
23588
23657
  function parsePoolMin(raw, dflt) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.306",
3
+ "version": "0.4.307",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -12,28 +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:all": "vitest run tests --no-coverage",
29
- "typecheck": "tsc --noEmit",
30
- "lint": "biome check",
31
- "lint:fix": "biome check --write",
32
- "format": "biome format --write",
33
- "verify:package": "node scripts/verify-package-tarball.cjs",
34
- "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner",
35
- "prepublishOnly": "pnpm typecheck && vitest run tests/unit tests/int --no-coverage && pnpm build && pnpm verify:package"
36
- },
37
15
  "dependencies": {
38
16
  "@actions/cache": "^6.0.0",
39
17
  "@anthropic-ai/claude-agent-sdk": "0.2.119",
@@ -57,5 +35,26 @@
57
35
  "url": "git+https://github.com/aharonyaircohen/kody-engine.git"
58
36
  },
59
37
  "homepage": "https://github.com/aharonyaircohen/kody-engine",
60
- "bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
61
- }
38
+ "bugs": "https://github.com/aharonyaircohen/kody-engine/issues",
39
+ "scripts": {
40
+ "kody:run": "tsx bin/kody.ts",
41
+ "serve": "tsx bin/kody.ts serve",
42
+ "serve:vscode": "tsx bin/kody.ts serve vscode",
43
+ "serve:claude": "tsx bin/kody.ts serve claude",
44
+ "clean:dist": "node scripts/clean-dist.cjs",
45
+ "build": "pnpm clean:dist && tsup && node scripts/copy-assets.cjs",
46
+ "check:modularity": "tsx scripts/check-script-modularity.ts",
47
+ "pretest": "pnpm check:modularity",
48
+ "test": "vitest run tests/unit tests/int --coverage",
49
+ "posttest": "tsx scripts/check-coverage-floor.ts",
50
+ "test:smoke": "vitest run tests/smoke --no-coverage",
51
+ "test:e2e": "vitest run tests/e2e --no-coverage",
52
+ "test:all": "vitest run tests --no-coverage",
53
+ "typecheck": "tsc --noEmit",
54
+ "lint": "biome check",
55
+ "lint:fix": "biome check --write",
56
+ "format": "biome format --write",
57
+ "verify:package": "node scripts/verify-package-tarball.cjs",
58
+ "brain:publish": "docker buildx build --platform linux/amd64 -f runner/Dockerfile.brain -t ghcr.io/${KODY_BRAIN_GHCR_OWNER:-aharonyaircohen}/kody-brain:latest --push runner"
59
+ }
60
+ }