@kody-ade/kody-engine 0.4.187 → 0.4.189
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 +134 -36
- package/dist/executables/goal-scheduler/scheduler.sh +0 -0
- package/dist/executables/release-deploy/deploy.sh +0 -0
- package/dist/executables/release-prepare/prepare.sh +0 -0
- package/dist/executables/release-publish/publish.sh +0 -0
- package/dist/executables/resolve/apply-prefer.sh +0 -0
- package/dist/executables/revert/revert.sh +0 -0
- package/package.json +21 -20
- package/templates/kody.yml +1 -0
package/dist/bin/kody.js
CHANGED
|
@@ -1309,7 +1309,7 @@ var init_loadPriorArt = __esm({
|
|
|
1309
1309
|
// package.json
|
|
1310
1310
|
var package_default = {
|
|
1311
1311
|
name: "@kody-ade/kody-engine",
|
|
1312
|
-
version: "0.4.
|
|
1312
|
+
version: "0.4.189",
|
|
1313
1313
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
1314
1314
|
license: "MIT",
|
|
1315
1315
|
type: "module",
|
|
@@ -2215,11 +2215,15 @@ async function runAgent(opts) {
|
|
|
2215
2215
|
);
|
|
2216
2216
|
}
|
|
2217
2217
|
finalText = resultTexts.join("\n\n---\n\n");
|
|
2218
|
-
if (outcome === "completed" && !sawMutatingTool
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2218
|
+
if (outcome === "completed" && !sawMutatingTool) {
|
|
2219
|
+
const backendDead = opts.isBackendHealthy ? !await opts.isBackendHealthy() : false;
|
|
2220
|
+
const zeroOutput = tokens.output === 0 && finalText === "";
|
|
2221
|
+
if (backendDead || zeroOutput) {
|
|
2222
|
+
outcome = "failed";
|
|
2223
|
+
outcomeKind = "model_error";
|
|
2224
|
+
noWorkSuccess = true;
|
|
2225
|
+
errorMessage = errorMessage ?? (backendDead ? "model backend unreachable after a reported success \u2014 proxy crashed mid-request (hollow success)" : "session reported success but produced no model output (0 output tokens) \u2014 backend likely unreachable");
|
|
2226
|
+
}
|
|
2223
2227
|
}
|
|
2224
2228
|
const shouldRetry = outcome === "failed" && attempt < MAX_CONNECTION_RETRIES && !sawMutatingTool && (isTransientConnectionError(errorMessage) || noWorkSuccess);
|
|
2225
2229
|
if (!shouldRetry) break;
|
|
@@ -4281,8 +4285,9 @@ ${tail}
|
|
|
4281
4285
|
spawnProxy();
|
|
4282
4286
|
return waitForHealth();
|
|
4283
4287
|
};
|
|
4288
|
+
const isHealthy = () => checkLitellmHealth(url);
|
|
4284
4289
|
if (await checkLitellmHealth(url)) {
|
|
4285
|
-
return { url, kill: killChild, ensureHealthy };
|
|
4290
|
+
return { url, kill: killChild, isHealthy, ensureHealthy };
|
|
4286
4291
|
}
|
|
4287
4292
|
spawnProxy();
|
|
4288
4293
|
if (!await waitForHealth()) {
|
|
@@ -4294,7 +4299,7 @@ ${tail}
|
|
|
4294
4299
|
${tail}`
|
|
4295
4300
|
);
|
|
4296
4301
|
}
|
|
4297
|
-
return { url, kill: killChild, ensureHealthy };
|
|
4302
|
+
return { url, kill: killChild, isHealthy, ensureHealthy };
|
|
4298
4303
|
}
|
|
4299
4304
|
function readDotenvApiKeys(projectDir) {
|
|
4300
4305
|
const dotenvPath = path14.join(projectDir, ".env");
|
|
@@ -12360,10 +12365,79 @@ async function runCmd(cmd, args, opts = {}) {
|
|
|
12360
12365
|
});
|
|
12361
12366
|
}
|
|
12362
12367
|
|
|
12368
|
+
// src/scripts/previewBuildNamespace.ts
|
|
12369
|
+
var NSC_OIDC_AUDIENCE = "https://namespace.so";
|
|
12370
|
+
var REQ_TIMEOUT_MS = 15e3;
|
|
12371
|
+
var NSC_INSTALL = `
|
|
12372
|
+
set -euo pipefail
|
|
12373
|
+
if [ ! -x /usr/local/bin/nsc ]; then
|
|
12374
|
+
ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/')
|
|
12375
|
+
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
12376
|
+
curl -fsSL "https://get.namespace.so/packages/nsc/latest?arch=\${ARCH}&os=\${OS}" -o /tmp/nsc.tar.gz
|
|
12377
|
+
mkdir -p /tmp/nsc-extract
|
|
12378
|
+
tar -xzf /tmp/nsc.tar.gz -C /tmp/nsc-extract
|
|
12379
|
+
NSC_BIN=$(find /tmp/nsc-extract -type f -name nsc | head -1)
|
|
12380
|
+
sudo install -m 0755 "$NSC_BIN" /usr/local/bin/nsc
|
|
12381
|
+
fi
|
|
12382
|
+
/usr/local/bin/nsc version
|
|
12383
|
+
`;
|
|
12384
|
+
async function fetchGithubOidcToken(audience) {
|
|
12385
|
+
const url = process.env.ACTIONS_ID_TOKEN_REQUEST_URL?.trim();
|
|
12386
|
+
const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN?.trim();
|
|
12387
|
+
if (!url || !requestToken) return null;
|
|
12388
|
+
const res = await fetch(`${url}&audience=${encodeURIComponent(audience)}`, {
|
|
12389
|
+
headers: { Authorization: `Bearer ${requestToken}` },
|
|
12390
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
|
|
12391
|
+
});
|
|
12392
|
+
if (!res.ok) {
|
|
12393
|
+
throw new Error(`OIDC token request failed: ${res.status} ${res.statusText}`);
|
|
12394
|
+
}
|
|
12395
|
+
const data = await res.json();
|
|
12396
|
+
if (!data.value) throw new Error("OIDC token response missing `value`");
|
|
12397
|
+
return data.value;
|
|
12398
|
+
}
|
|
12399
|
+
async function setupNamespaceBuilder(opts) {
|
|
12400
|
+
try {
|
|
12401
|
+
await runCmd("bash", ["-c", NSC_INSTALL]);
|
|
12402
|
+
const jwt = await fetchGithubOidcToken(NSC_OIDC_AUDIENCE);
|
|
12403
|
+
if (!jwt) {
|
|
12404
|
+
console.warn(
|
|
12405
|
+
"[preview-build] no GitHub OIDC token (id-token: write missing?) \u2014 local docker build"
|
|
12406
|
+
);
|
|
12407
|
+
return null;
|
|
12408
|
+
}
|
|
12409
|
+
await runCmd("nsc", [
|
|
12410
|
+
"auth",
|
|
12411
|
+
"exchange-oidc-token",
|
|
12412
|
+
"--tenant_id",
|
|
12413
|
+
opts.tenantId,
|
|
12414
|
+
"--token",
|
|
12415
|
+
jwt
|
|
12416
|
+
]);
|
|
12417
|
+
await runCmd("nsc", [
|
|
12418
|
+
"docker",
|
|
12419
|
+
"buildx",
|
|
12420
|
+
"setup",
|
|
12421
|
+
"--name",
|
|
12422
|
+
opts.builderName
|
|
12423
|
+
]);
|
|
12424
|
+
console.log(
|
|
12425
|
+
`[preview-build] Namespace remote builder ready (${opts.builderName})`
|
|
12426
|
+
);
|
|
12427
|
+
return opts.builderName;
|
|
12428
|
+
} catch (err) {
|
|
12429
|
+
console.warn(
|
|
12430
|
+
"[preview-build] Namespace setup failed \u2014 falling back to local docker:",
|
|
12431
|
+
err instanceof Error ? err.message : String(err)
|
|
12432
|
+
);
|
|
12433
|
+
return null;
|
|
12434
|
+
}
|
|
12435
|
+
}
|
|
12436
|
+
|
|
12363
12437
|
// src/scripts/runPreviewBuild.ts
|
|
12364
12438
|
var FLY_MACHINES = "https://api.machines.dev/v1";
|
|
12365
12439
|
var FLY_GRAPHQL = "https://api.fly.io/graphql";
|
|
12366
|
-
var
|
|
12440
|
+
var REQ_TIMEOUT_MS2 = 3e4;
|
|
12367
12441
|
function bundledDockerfilePath(mode) {
|
|
12368
12442
|
const here = path36.dirname(fileURLToPath(import.meta.url));
|
|
12369
12443
|
const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
|
|
@@ -12387,7 +12461,7 @@ async function ghJSON(url, token) {
|
|
|
12387
12461
|
Accept: "application/vnd.github+json",
|
|
12388
12462
|
"X-GitHub-Api-Version": "2022-11-28"
|
|
12389
12463
|
},
|
|
12390
|
-
signal: AbortSignal.timeout(
|
|
12464
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12391
12465
|
});
|
|
12392
12466
|
if (!res.ok) {
|
|
12393
12467
|
throw new Error(`GitHub ${url}: ${res.status} ${res.statusText}`);
|
|
@@ -12406,7 +12480,7 @@ async function fetchVaultDoc(repo, ghToken4, masterKey) {
|
|
|
12406
12480
|
async function flyAppExists(name, token) {
|
|
12407
12481
|
const res = await fetch(`${FLY_MACHINES}/apps/${encodeURIComponent(name)}`, {
|
|
12408
12482
|
headers: flyHeaders(token),
|
|
12409
|
-
signal: AbortSignal.timeout(
|
|
12483
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12410
12484
|
});
|
|
12411
12485
|
if (res.status === 404) return false;
|
|
12412
12486
|
if (!res.ok) {
|
|
@@ -12419,7 +12493,7 @@ async function flyCreateApp(name, orgSlug, token) {
|
|
|
12419
12493
|
method: "POST",
|
|
12420
12494
|
headers: flyHeaders(token),
|
|
12421
12495
|
body: JSON.stringify({ app_name: name, org_slug: orgSlug }),
|
|
12422
|
-
signal: AbortSignal.timeout(
|
|
12496
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12423
12497
|
});
|
|
12424
12498
|
if (res.status === 422) return;
|
|
12425
12499
|
if (!res.ok) {
|
|
@@ -12438,7 +12512,7 @@ async function flyAllocateSharedIps(appName, token) {
|
|
|
12438
12512
|
method: "POST",
|
|
12439
12513
|
headers: flyHeaders(token),
|
|
12440
12514
|
body: JSON.stringify({ query: mutation, variables: { appId: appName } }),
|
|
12441
|
-
signal: AbortSignal.timeout(
|
|
12515
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12442
12516
|
});
|
|
12443
12517
|
if (!res.ok) {
|
|
12444
12518
|
throw new Error(`allocateSharedIps ${appName}: ${res.status}`);
|
|
@@ -12456,7 +12530,7 @@ async function flyListMachines(appName, token) {
|
|
|
12456
12530
|
`${FLY_MACHINES}/apps/${encodeURIComponent(appName)}/machines`,
|
|
12457
12531
|
{
|
|
12458
12532
|
headers: flyHeaders(token),
|
|
12459
|
-
signal: AbortSignal.timeout(
|
|
12533
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12460
12534
|
}
|
|
12461
12535
|
);
|
|
12462
12536
|
if (res.status === 404) return [];
|
|
@@ -12472,7 +12546,7 @@ async function flyDestroyMachine(appName, machineId, token) {
|
|
|
12472
12546
|
{
|
|
12473
12547
|
method: "POST",
|
|
12474
12548
|
headers: flyHeaders(token),
|
|
12475
|
-
signal: AbortSignal.timeout(
|
|
12549
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12476
12550
|
}
|
|
12477
12551
|
).catch(() => void 0);
|
|
12478
12552
|
const res = await fetch(
|
|
@@ -12480,7 +12554,7 @@ async function flyDestroyMachine(appName, machineId, token) {
|
|
|
12480
12554
|
{
|
|
12481
12555
|
method: "DELETE",
|
|
12482
12556
|
headers: flyHeaders(token),
|
|
12483
|
-
signal: AbortSignal.timeout(
|
|
12557
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12484
12558
|
}
|
|
12485
12559
|
);
|
|
12486
12560
|
if (res.status === 404) return;
|
|
@@ -12533,7 +12607,7 @@ async function flyCreatePreviewMachine(args, token) {
|
|
|
12533
12607
|
method: "POST",
|
|
12534
12608
|
headers: flyHeaders(token),
|
|
12535
12609
|
body: JSON.stringify(body),
|
|
12536
|
-
signal: AbortSignal.timeout(
|
|
12610
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12537
12611
|
}
|
|
12538
12612
|
);
|
|
12539
12613
|
if (res.ok) {
|
|
@@ -12560,7 +12634,7 @@ async function postOrUpdatePreviewComment(args) {
|
|
|
12560
12634
|
};
|
|
12561
12635
|
const listRes = await fetch(`${base}?per_page=100`, {
|
|
12562
12636
|
headers,
|
|
12563
|
-
signal: AbortSignal.timeout(
|
|
12637
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12564
12638
|
}).catch(() => null);
|
|
12565
12639
|
let existingId = null;
|
|
12566
12640
|
if (listRes && listRes.ok) {
|
|
@@ -12575,7 +12649,7 @@ async function postOrUpdatePreviewComment(args) {
|
|
|
12575
12649
|
method: "PATCH",
|
|
12576
12650
|
headers,
|
|
12577
12651
|
body: JSON.stringify({ body: args.body }),
|
|
12578
|
-
signal: AbortSignal.timeout(
|
|
12652
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12579
12653
|
}
|
|
12580
12654
|
);
|
|
12581
12655
|
return;
|
|
@@ -12584,7 +12658,7 @@ async function postOrUpdatePreviewComment(args) {
|
|
|
12584
12658
|
method: "POST",
|
|
12585
12659
|
headers,
|
|
12586
12660
|
body: JSON.stringify({ body: args.body }),
|
|
12587
|
-
signal: AbortSignal.timeout(
|
|
12661
|
+
signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
|
|
12588
12662
|
});
|
|
12589
12663
|
}
|
|
12590
12664
|
var runPreviewBuild = async (ctx, _profile, _args) => {
|
|
@@ -12628,6 +12702,7 @@ var runPreviewBuild = async (ctx, _profile, _args) => {
|
|
|
12628
12702
|
}
|
|
12629
12703
|
const orgSlug = doc.secrets?.FLY_ORG_SLUG?.value?.trim() || (process.env.FLY_ORG_SLUG ?? "personal").trim();
|
|
12630
12704
|
const region = doc.secrets?.FLY_DEFAULT_REGION?.value?.trim() || (process.env.FLY_REGION ?? "fra").trim();
|
|
12705
|
+
const nscTenantId = doc.secrets?.NSC_TENANT_ID?.value?.trim() || "";
|
|
12631
12706
|
console.log(
|
|
12632
12707
|
`[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`
|
|
12633
12708
|
);
|
|
@@ -12691,22 +12766,42 @@ var runPreviewBuild = async (ctx, _profile, _args) => {
|
|
|
12691
12766
|
["login", "registry.fly.io", "-u", "x", "--password-stdin"],
|
|
12692
12767
|
{ input: flyToken, cwd: ctx.cwd }
|
|
12693
12768
|
);
|
|
12694
|
-
const
|
|
12695
|
-
|
|
12696
|
-
|
|
12697
|
-
|
|
12698
|
-
|
|
12699
|
-
|
|
12700
|
-
|
|
12701
|
-
|
|
12702
|
-
|
|
12703
|
-
|
|
12704
|
-
|
|
12705
|
-
|
|
12706
|
-
|
|
12707
|
-
|
|
12708
|
-
|
|
12709
|
-
|
|
12769
|
+
const imageRef = `registry.fly.io/${appName}:${tag}`;
|
|
12770
|
+
const nsBuilder = nscTenantId ? await setupNamespaceBuilder({
|
|
12771
|
+
tenantId: nscTenantId,
|
|
12772
|
+
builderName: `kody-preview-${pr}`
|
|
12773
|
+
}) : null;
|
|
12774
|
+
if (nsBuilder) {
|
|
12775
|
+
const a = [
|
|
12776
|
+
"buildx",
|
|
12777
|
+
"build",
|
|
12778
|
+
"--builder",
|
|
12779
|
+
nsBuilder,
|
|
12780
|
+
"-f",
|
|
12781
|
+
"Dockerfile.preview",
|
|
12782
|
+
"-t",
|
|
12783
|
+
imageRef,
|
|
12784
|
+
"--push"
|
|
12785
|
+
];
|
|
12786
|
+
if (baseImage) a.push("--build-arg", `BASE_IMAGE=${baseImage}`);
|
|
12787
|
+
a.push(".");
|
|
12788
|
+
await runCmd("docker", a, { cwd: ctx.cwd });
|
|
12789
|
+
} else {
|
|
12790
|
+
const buildArgs = [
|
|
12791
|
+
"build",
|
|
12792
|
+
"-f",
|
|
12793
|
+
"Dockerfile.preview",
|
|
12794
|
+
"-t",
|
|
12795
|
+
imageRef
|
|
12796
|
+
];
|
|
12797
|
+
if (baseImage) buildArgs.push("--build-arg", `BASE_IMAGE=${baseImage}`);
|
|
12798
|
+
buildArgs.push(".");
|
|
12799
|
+
await runCmd("docker", buildArgs, {
|
|
12800
|
+
cwd: ctx.cwd,
|
|
12801
|
+
env: { DOCKER_BUILDKIT: "1" }
|
|
12802
|
+
});
|
|
12803
|
+
await runCmd("docker", ["push", imageRef], { cwd: ctx.cwd });
|
|
12804
|
+
}
|
|
12710
12805
|
const stale = await flyListMachines(appName, flyToken);
|
|
12711
12806
|
for (const m of stale) {
|
|
12712
12807
|
await flyDestroyMachine(appName, m.id, flyToken).catch(() => void 0);
|
|
@@ -14187,6 +14282,9 @@ async function runExecutable(profileName, input) {
|
|
|
14187
14282
|
// On a connection drop mid-run, restart the (possibly crashed) proxy
|
|
14188
14283
|
// before the agent retries. No-op for direct-Anthropic runs (lm null).
|
|
14189
14284
|
ensureBackend: lm ? () => lm.ensureHealthy().then(() => void 0) : void 0,
|
|
14285
|
+
// Pure liveness probe so the agent can spot a hollow "success" (proxy
|
|
14286
|
+
// crashed mid-request, SDK still reported success). No-op when lm null.
|
|
14287
|
+
isBackendHealthy: lm ? () => lm.isHealthy() : void 0,
|
|
14190
14288
|
verbose: input.verbose,
|
|
14191
14289
|
quiet: input.quiet,
|
|
14192
14290
|
ndjsonDir,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
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.189",
|
|
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,6 +12,24 @@
|
|
|
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
|
+
"build": "tsup && node scripts/copy-assets.cjs",
|
|
21
|
+
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
22
|
+
"pretest": "pnpm check:modularity",
|
|
23
|
+
"test": "vitest run tests/unit tests/int --coverage",
|
|
24
|
+
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
25
|
+
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
26
|
+
"test:all": "vitest run tests --no-coverage",
|
|
27
|
+
"typecheck": "tsc --noEmit",
|
|
28
|
+
"lint": "biome check",
|
|
29
|
+
"lint:fix": "biome check --write",
|
|
30
|
+
"format": "biome format --write",
|
|
31
|
+
"prepublishOnly": "pnpm build"
|
|
32
|
+
},
|
|
15
33
|
"dependencies": {
|
|
16
34
|
"@actions/cache": "^6.0.0",
|
|
17
35
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
@@ -34,22 +52,5 @@
|
|
|
34
52
|
"url": "git+https://github.com/aharonyaircohen/kody-engine.git"
|
|
35
53
|
},
|
|
36
54
|
"homepage": "https://github.com/aharonyaircohen/kody-engine",
|
|
37
|
-
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
38
|
-
|
|
39
|
-
"kody:run": "tsx bin/kody.ts",
|
|
40
|
-
"serve": "tsx bin/kody.ts serve",
|
|
41
|
-
"serve:vscode": "tsx bin/kody.ts serve vscode",
|
|
42
|
-
"serve:claude": "tsx bin/kody.ts serve claude",
|
|
43
|
-
"build": "tsup && node scripts/copy-assets.cjs",
|
|
44
|
-
"check:modularity": "tsx scripts/check-script-modularity.ts",
|
|
45
|
-
"pretest": "pnpm check:modularity",
|
|
46
|
-
"test": "vitest run tests/unit tests/int --coverage",
|
|
47
|
-
"test:smoke": "vitest run tests/smoke --no-coverage",
|
|
48
|
-
"test:e2e": "vitest run tests/e2e --no-coverage",
|
|
49
|
-
"test:all": "vitest run tests --no-coverage",
|
|
50
|
-
"typecheck": "tsc --noEmit",
|
|
51
|
-
"lint": "biome check",
|
|
52
|
-
"lint:fix": "biome check --write",
|
|
53
|
-
"format": "biome format --write"
|
|
54
|
-
}
|
|
55
|
-
}
|
|
55
|
+
"bugs": "https://github.com/aharonyaircohen/kody-engine/issues"
|
|
56
|
+
}
|