@kody-ade/kody-engine 0.4.123 → 0.4.124
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 +103 -122
- package/package.json +1 -1
package/dist/bin/kody.js
CHANGED
|
@@ -880,7 +880,7 @@ var init_loadPriorArt = __esm({
|
|
|
880
880
|
// package.json
|
|
881
881
|
var package_default = {
|
|
882
882
|
name: "@kody-ade/kody-engine",
|
|
883
|
-
version: "0.4.
|
|
883
|
+
version: "0.4.124",
|
|
884
884
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
885
885
|
license: "MIT",
|
|
886
886
|
type: "module",
|
|
@@ -8540,107 +8540,6 @@ init_loadPriorArt();
|
|
|
8540
8540
|
import * as fs34 from "fs";
|
|
8541
8541
|
import * as path33 from "path";
|
|
8542
8542
|
|
|
8543
|
-
// src/pool/keys.ts
|
|
8544
|
-
import { hkdfSync } from "crypto";
|
|
8545
|
-
var POOL_API_KEY_INFO = "kody-pool-api:v1";
|
|
8546
|
-
var RUNNER_API_KEY_INFO = "kody-runner-api:v1";
|
|
8547
|
-
function masterKeyBytes(raw) {
|
|
8548
|
-
const v = raw.trim();
|
|
8549
|
-
if (!v) throw new Error("KODY_MASTER_KEY is empty");
|
|
8550
|
-
if (/^[0-9a-fA-F]+$/.test(v) && v.length === 64) {
|
|
8551
|
-
return Buffer.from(v, "hex");
|
|
8552
|
-
}
|
|
8553
|
-
return Buffer.from(v.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
8554
|
-
}
|
|
8555
|
-
function deriveKey(master, info, length = 32) {
|
|
8556
|
-
return Buffer.from(hkdfSync("sha256", master, Buffer.alloc(0), info, length)).toString("hex");
|
|
8557
|
-
}
|
|
8558
|
-
function derivePoolApiKey(master) {
|
|
8559
|
-
return deriveKey(master, POOL_API_KEY_INFO);
|
|
8560
|
-
}
|
|
8561
|
-
function deriveRunnerApiKey(master) {
|
|
8562
|
-
return deriveKey(master, RUNNER_API_KEY_INFO);
|
|
8563
|
-
}
|
|
8564
|
-
function bearerOk(headerAuth, xApiKey, expected) {
|
|
8565
|
-
const x = (xApiKey ?? "").trim();
|
|
8566
|
-
if (x && timingEqual(x, expected)) return true;
|
|
8567
|
-
const a = (headerAuth ?? "").trim();
|
|
8568
|
-
if (a.toLowerCase().startsWith("bearer ")) {
|
|
8569
|
-
return timingEqual(a.slice(7).trim(), expected);
|
|
8570
|
-
}
|
|
8571
|
-
return false;
|
|
8572
|
-
}
|
|
8573
|
-
function timingEqual(a, b) {
|
|
8574
|
-
if (a.length !== b.length) return false;
|
|
8575
|
-
let diff = 0;
|
|
8576
|
-
for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
8577
|
-
return diff === 0;
|
|
8578
|
-
}
|
|
8579
|
-
|
|
8580
|
-
// src/pool/vault.ts
|
|
8581
|
-
import { createDecipheriv } from "crypto";
|
|
8582
|
-
var GITHUB_API = "https://api.github.com";
|
|
8583
|
-
var VAULT_PATH = ".kody/secrets.enc";
|
|
8584
|
-
var CACHE_TTL_MS = 6e4;
|
|
8585
|
-
var cache = /* @__PURE__ */ new Map();
|
|
8586
|
-
function decryptVault(payload, masterKey) {
|
|
8587
|
-
const parts = payload.split(":");
|
|
8588
|
-
if (parts.length !== 4 || parts[0] !== "v1") {
|
|
8589
|
-
throw new Error("invalid vault payload format");
|
|
8590
|
-
}
|
|
8591
|
-
const [, ivB64, ctB64, tagB64] = parts;
|
|
8592
|
-
const iv = Buffer.from(ivB64, "base64");
|
|
8593
|
-
const ct = Buffer.from(ctB64, "base64");
|
|
8594
|
-
const tag = Buffer.from(tagB64, "base64");
|
|
8595
|
-
const decipher = createDecipheriv("aes-256-gcm", masterKey, iv);
|
|
8596
|
-
decipher.setAuthTag(tag);
|
|
8597
|
-
return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
|
|
8598
|
-
}
|
|
8599
|
-
async function readVaultSecrets(opts) {
|
|
8600
|
-
const key = `${opts.owner}/${opts.repo}`.toLowerCase();
|
|
8601
|
-
const hit = cache.get(key);
|
|
8602
|
-
if (hit && hit.expiresAt > Date.now()) return hit.secrets;
|
|
8603
|
-
const doFetch = opts.fetchImpl ?? fetch;
|
|
8604
|
-
const res = await doFetch(
|
|
8605
|
-
`${GITHUB_API}/repos/${encodeURIComponent(opts.owner)}/${encodeURIComponent(opts.repo)}/contents/${VAULT_PATH}`,
|
|
8606
|
-
{
|
|
8607
|
-
headers: {
|
|
8608
|
-
Authorization: `Bearer ${opts.githubToken}`,
|
|
8609
|
-
Accept: "application/vnd.github+json",
|
|
8610
|
-
"User-Agent": "kody-pool-serve"
|
|
8611
|
-
}
|
|
8612
|
-
}
|
|
8613
|
-
);
|
|
8614
|
-
if (res.status === 404) {
|
|
8615
|
-
cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
8616
|
-
return {};
|
|
8617
|
-
}
|
|
8618
|
-
if (!res.ok) {
|
|
8619
|
-
throw new Error(`vault read ${res.status} for ${key}: ${(await res.text().catch(() => "")).slice(0, 160)}`);
|
|
8620
|
-
}
|
|
8621
|
-
const body = await res.json();
|
|
8622
|
-
if (!body.content) {
|
|
8623
|
-
cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
8624
|
-
return {};
|
|
8625
|
-
}
|
|
8626
|
-
const ciphertext = Buffer.from(body.content, body.encoding ?? "base64").toString("utf8").trim();
|
|
8627
|
-
const doc = JSON.parse(decryptVault(ciphertext, opts.masterKey));
|
|
8628
|
-
const flat = {};
|
|
8629
|
-
for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
|
|
8630
|
-
if (entry && typeof entry.value === "string") flat[name] = entry.value;
|
|
8631
|
-
}
|
|
8632
|
-
cache.set(key, { secrets: flat, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
8633
|
-
return flat;
|
|
8634
|
-
}
|
|
8635
|
-
async function readRepoSecret(opts) {
|
|
8636
|
-
const secrets = await readVaultSecrets(opts);
|
|
8637
|
-
const v = secrets[opts.name];
|
|
8638
|
-
return v && v.trim() ? v : null;
|
|
8639
|
-
}
|
|
8640
|
-
async function readRepoSecrets(opts) {
|
|
8641
|
-
return readVaultSecrets(opts);
|
|
8642
|
-
}
|
|
8643
|
-
|
|
8644
8543
|
// src/scripts/kodyVariables.ts
|
|
8645
8544
|
import * as fs33 from "fs";
|
|
8646
8545
|
import * as path32 from "path";
|
|
@@ -8667,26 +8566,7 @@ function readKodyVariables(cwd) {
|
|
|
8667
8566
|
}
|
|
8668
8567
|
|
|
8669
8568
|
// src/scripts/loadQaContext.ts
|
|
8670
|
-
var VAULT_REL_PATH = ".kody/secrets.enc";
|
|
8671
8569
|
var PROFILE_DIR_REL_PATH = ".kody/profile";
|
|
8672
|
-
function readVaultPassword(cwd) {
|
|
8673
|
-
const rawKey = process.env.KODY_MASTER_KEY;
|
|
8674
|
-
if (!rawKey) return "";
|
|
8675
|
-
const vaultPath = path33.join(cwd, VAULT_REL_PATH);
|
|
8676
|
-
if (!fs34.existsSync(vaultPath)) return "";
|
|
8677
|
-
try {
|
|
8678
|
-
const payload = fs34.readFileSync(vaultPath, "utf-8").trim();
|
|
8679
|
-
const doc = JSON.parse(decryptVault(payload, masterKeyBytes(rawKey)));
|
|
8680
|
-
const entry = doc.secrets?.LOGIN_PASSWORD;
|
|
8681
|
-
if (entry && typeof entry.value === "string" && entry.value.length > 0) return entry.value;
|
|
8682
|
-
return "";
|
|
8683
|
-
} catch (err) {
|
|
8684
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
8685
|
-
process.stderr.write(`[loadQaContext] could not read LOGIN_PASSWORD from vault: ${msg}
|
|
8686
|
-
`);
|
|
8687
|
-
return "";
|
|
8688
|
-
}
|
|
8689
|
-
}
|
|
8690
8570
|
function readProfile(cwd) {
|
|
8691
8571
|
const dir = path33.join(cwd, PROFILE_DIR_REL_PATH);
|
|
8692
8572
|
if (!fs34.existsSync(dir)) return "";
|
|
@@ -8723,7 +8603,7 @@ function composeAuthBlock(authProfile, login, password) {
|
|
|
8723
8603
|
var loadQaContext = async (ctx) => {
|
|
8724
8604
|
const vars = readKodyVariables(ctx.cwd);
|
|
8725
8605
|
const login = vars.LOGIN_USER ?? "";
|
|
8726
|
-
const password =
|
|
8606
|
+
const password = process.env.LOGIN_PASSWORD ?? "";
|
|
8727
8607
|
const authProfile = ctx.args.authProfile;
|
|
8728
8608
|
ctx.data.qaLogin = login;
|
|
8729
8609
|
ctx.data.qaProfile = readProfile(ctx.cwd);
|
|
@@ -9671,6 +9551,70 @@ function errMsg2(err) {
|
|
|
9671
9551
|
return err instanceof Error ? err.message : String(err);
|
|
9672
9552
|
}
|
|
9673
9553
|
|
|
9554
|
+
// src/pool/vault.ts
|
|
9555
|
+
import { createDecipheriv } from "crypto";
|
|
9556
|
+
var GITHUB_API = "https://api.github.com";
|
|
9557
|
+
var VAULT_PATH = ".kody/secrets.enc";
|
|
9558
|
+
var CACHE_TTL_MS = 6e4;
|
|
9559
|
+
var cache = /* @__PURE__ */ new Map();
|
|
9560
|
+
function decryptVault(payload, masterKey) {
|
|
9561
|
+
const parts = payload.split(":");
|
|
9562
|
+
if (parts.length !== 4 || parts[0] !== "v1") {
|
|
9563
|
+
throw new Error("invalid vault payload format");
|
|
9564
|
+
}
|
|
9565
|
+
const [, ivB64, ctB64, tagB64] = parts;
|
|
9566
|
+
const iv = Buffer.from(ivB64, "base64");
|
|
9567
|
+
const ct = Buffer.from(ctB64, "base64");
|
|
9568
|
+
const tag = Buffer.from(tagB64, "base64");
|
|
9569
|
+
const decipher = createDecipheriv("aes-256-gcm", masterKey, iv);
|
|
9570
|
+
decipher.setAuthTag(tag);
|
|
9571
|
+
return Buffer.concat([decipher.update(ct), decipher.final()]).toString("utf8");
|
|
9572
|
+
}
|
|
9573
|
+
async function readVaultSecrets(opts) {
|
|
9574
|
+
const key = `${opts.owner}/${opts.repo}`.toLowerCase();
|
|
9575
|
+
const hit = cache.get(key);
|
|
9576
|
+
if (hit && hit.expiresAt > Date.now()) return hit.secrets;
|
|
9577
|
+
const doFetch = opts.fetchImpl ?? fetch;
|
|
9578
|
+
const res = await doFetch(
|
|
9579
|
+
`${GITHUB_API}/repos/${encodeURIComponent(opts.owner)}/${encodeURIComponent(opts.repo)}/contents/${VAULT_PATH}`,
|
|
9580
|
+
{
|
|
9581
|
+
headers: {
|
|
9582
|
+
Authorization: `Bearer ${opts.githubToken}`,
|
|
9583
|
+
Accept: "application/vnd.github+json",
|
|
9584
|
+
"User-Agent": "kody-pool-serve"
|
|
9585
|
+
}
|
|
9586
|
+
}
|
|
9587
|
+
);
|
|
9588
|
+
if (res.status === 404) {
|
|
9589
|
+
cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
9590
|
+
return {};
|
|
9591
|
+
}
|
|
9592
|
+
if (!res.ok) {
|
|
9593
|
+
throw new Error(`vault read ${res.status} for ${key}: ${(await res.text().catch(() => "")).slice(0, 160)}`);
|
|
9594
|
+
}
|
|
9595
|
+
const body = await res.json();
|
|
9596
|
+
if (!body.content) {
|
|
9597
|
+
cache.set(key, { secrets: {}, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
9598
|
+
return {};
|
|
9599
|
+
}
|
|
9600
|
+
const ciphertext = Buffer.from(body.content, body.encoding ?? "base64").toString("utf8").trim();
|
|
9601
|
+
const doc = JSON.parse(decryptVault(ciphertext, opts.masterKey));
|
|
9602
|
+
const flat = {};
|
|
9603
|
+
for (const [name, entry] of Object.entries(doc.secrets ?? {})) {
|
|
9604
|
+
if (entry && typeof entry.value === "string") flat[name] = entry.value;
|
|
9605
|
+
}
|
|
9606
|
+
cache.set(key, { secrets: flat, expiresAt: Date.now() + CACHE_TTL_MS });
|
|
9607
|
+
return flat;
|
|
9608
|
+
}
|
|
9609
|
+
async function readRepoSecret(opts) {
|
|
9610
|
+
const secrets = await readVaultSecrets(opts);
|
|
9611
|
+
const v = secrets[opts.name];
|
|
9612
|
+
return v && v.trim() ? v : null;
|
|
9613
|
+
}
|
|
9614
|
+
async function readRepoSecrets(opts) {
|
|
9615
|
+
return readVaultSecrets(opts);
|
|
9616
|
+
}
|
|
9617
|
+
|
|
9674
9618
|
// src/pool/registry.ts
|
|
9675
9619
|
var POOL_MIN_VAULT_KEY = "POOL_MIN";
|
|
9676
9620
|
var POOL_MIN_MAX = 10;
|
|
@@ -9800,6 +9744,43 @@ var PoolRegistry = class {
|
|
|
9800
9744
|
}
|
|
9801
9745
|
};
|
|
9802
9746
|
|
|
9747
|
+
// src/pool/keys.ts
|
|
9748
|
+
import { hkdfSync } from "crypto";
|
|
9749
|
+
var POOL_API_KEY_INFO = "kody-pool-api:v1";
|
|
9750
|
+
var RUNNER_API_KEY_INFO = "kody-runner-api:v1";
|
|
9751
|
+
function masterKeyBytes(raw) {
|
|
9752
|
+
const v = raw.trim();
|
|
9753
|
+
if (!v) throw new Error("KODY_MASTER_KEY is empty");
|
|
9754
|
+
if (/^[0-9a-fA-F]+$/.test(v) && v.length === 64) {
|
|
9755
|
+
return Buffer.from(v, "hex");
|
|
9756
|
+
}
|
|
9757
|
+
return Buffer.from(v.replace(/-/g, "+").replace(/_/g, "/"), "base64");
|
|
9758
|
+
}
|
|
9759
|
+
function deriveKey(master, info, length = 32) {
|
|
9760
|
+
return Buffer.from(hkdfSync("sha256", master, Buffer.alloc(0), info, length)).toString("hex");
|
|
9761
|
+
}
|
|
9762
|
+
function derivePoolApiKey(master) {
|
|
9763
|
+
return deriveKey(master, POOL_API_KEY_INFO);
|
|
9764
|
+
}
|
|
9765
|
+
function deriveRunnerApiKey(master) {
|
|
9766
|
+
return deriveKey(master, RUNNER_API_KEY_INFO);
|
|
9767
|
+
}
|
|
9768
|
+
function bearerOk(headerAuth, xApiKey, expected) {
|
|
9769
|
+
const x = (xApiKey ?? "").trim();
|
|
9770
|
+
if (x && timingEqual(x, expected)) return true;
|
|
9771
|
+
const a = (headerAuth ?? "").trim();
|
|
9772
|
+
if (a.toLowerCase().startsWith("bearer ")) {
|
|
9773
|
+
return timingEqual(a.slice(7).trim(), expected);
|
|
9774
|
+
}
|
|
9775
|
+
return false;
|
|
9776
|
+
}
|
|
9777
|
+
function timingEqual(a, b) {
|
|
9778
|
+
if (a.length !== b.length) return false;
|
|
9779
|
+
let diff = 0;
|
|
9780
|
+
for (let i = 0; i < a.length; i++) diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
|
|
9781
|
+
return diff === 0;
|
|
9782
|
+
}
|
|
9783
|
+
|
|
9803
9784
|
// src/scripts/poolServe.ts
|
|
9804
9785
|
var PERF_GUEST = {
|
|
9805
9786
|
low: { cpu_kind: "shared", cpus: 2, memory_mb: 2048 },
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.124",
|
|
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",
|