@kody-ade/kody-engine 0.4.188 → 0.4.190

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin/kody.js CHANGED
@@ -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.188",
1312
+ version: "0.4.190",
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",
@@ -12365,10 +12365,79 @@ async function runCmd(cmd, args, opts = {}) {
12365
12365
  });
12366
12366
  }
12367
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
+
12368
12437
  // src/scripts/runPreviewBuild.ts
12369
12438
  var FLY_MACHINES = "https://api.machines.dev/v1";
12370
12439
  var FLY_GRAPHQL = "https://api.fly.io/graphql";
12371
- var REQ_TIMEOUT_MS = 3e4;
12440
+ var REQ_TIMEOUT_MS2 = 3e4;
12372
12441
  function bundledDockerfilePath(mode) {
12373
12442
  const here = path36.dirname(fileURLToPath(import.meta.url));
12374
12443
  const file = mode === "dev" ? "default-Dockerfile.preview.dev" : "default-Dockerfile.preview.prod";
@@ -12392,7 +12461,7 @@ async function ghJSON(url, token) {
12392
12461
  Accept: "application/vnd.github+json",
12393
12462
  "X-GitHub-Api-Version": "2022-11-28"
12394
12463
  },
12395
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12464
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12396
12465
  });
12397
12466
  if (!res.ok) {
12398
12467
  throw new Error(`GitHub ${url}: ${res.status} ${res.statusText}`);
@@ -12411,7 +12480,7 @@ async function fetchVaultDoc(repo, ghToken4, masterKey) {
12411
12480
  async function flyAppExists(name, token) {
12412
12481
  const res = await fetch(`${FLY_MACHINES}/apps/${encodeURIComponent(name)}`, {
12413
12482
  headers: flyHeaders(token),
12414
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12483
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12415
12484
  });
12416
12485
  if (res.status === 404) return false;
12417
12486
  if (!res.ok) {
@@ -12424,7 +12493,7 @@ async function flyCreateApp(name, orgSlug, token) {
12424
12493
  method: "POST",
12425
12494
  headers: flyHeaders(token),
12426
12495
  body: JSON.stringify({ app_name: name, org_slug: orgSlug }),
12427
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12496
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12428
12497
  });
12429
12498
  if (res.status === 422) return;
12430
12499
  if (!res.ok) {
@@ -12443,7 +12512,7 @@ async function flyAllocateSharedIps(appName, token) {
12443
12512
  method: "POST",
12444
12513
  headers: flyHeaders(token),
12445
12514
  body: JSON.stringify({ query: mutation, variables: { appId: appName } }),
12446
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12515
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12447
12516
  });
12448
12517
  if (!res.ok) {
12449
12518
  throw new Error(`allocateSharedIps ${appName}: ${res.status}`);
@@ -12461,7 +12530,7 @@ async function flyListMachines(appName, token) {
12461
12530
  `${FLY_MACHINES}/apps/${encodeURIComponent(appName)}/machines`,
12462
12531
  {
12463
12532
  headers: flyHeaders(token),
12464
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12533
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12465
12534
  }
12466
12535
  );
12467
12536
  if (res.status === 404) return [];
@@ -12477,7 +12546,7 @@ async function flyDestroyMachine(appName, machineId, token) {
12477
12546
  {
12478
12547
  method: "POST",
12479
12548
  headers: flyHeaders(token),
12480
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12549
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12481
12550
  }
12482
12551
  ).catch(() => void 0);
12483
12552
  const res = await fetch(
@@ -12485,7 +12554,7 @@ async function flyDestroyMachine(appName, machineId, token) {
12485
12554
  {
12486
12555
  method: "DELETE",
12487
12556
  headers: flyHeaders(token),
12488
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12557
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12489
12558
  }
12490
12559
  );
12491
12560
  if (res.status === 404) return;
@@ -12538,7 +12607,7 @@ async function flyCreatePreviewMachine(args, token) {
12538
12607
  method: "POST",
12539
12608
  headers: flyHeaders(token),
12540
12609
  body: JSON.stringify(body),
12541
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12610
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12542
12611
  }
12543
12612
  );
12544
12613
  if (res.ok) {
@@ -12565,7 +12634,7 @@ async function postOrUpdatePreviewComment(args) {
12565
12634
  };
12566
12635
  const listRes = await fetch(`${base}?per_page=100`, {
12567
12636
  headers,
12568
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12637
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12569
12638
  }).catch(() => null);
12570
12639
  let existingId = null;
12571
12640
  if (listRes && listRes.ok) {
@@ -12580,7 +12649,7 @@ async function postOrUpdatePreviewComment(args) {
12580
12649
  method: "PATCH",
12581
12650
  headers,
12582
12651
  body: JSON.stringify({ body: args.body }),
12583
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12652
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12584
12653
  }
12585
12654
  );
12586
12655
  return;
@@ -12589,7 +12658,7 @@ async function postOrUpdatePreviewComment(args) {
12589
12658
  method: "POST",
12590
12659
  headers,
12591
12660
  body: JSON.stringify({ body: args.body }),
12592
- signal: AbortSignal.timeout(REQ_TIMEOUT_MS)
12661
+ signal: AbortSignal.timeout(REQ_TIMEOUT_MS2)
12593
12662
  });
12594
12663
  }
12595
12664
  var runPreviewBuild = async (ctx, _profile, _args) => {
@@ -12633,6 +12702,7 @@ var runPreviewBuild = async (ctx, _profile, _args) => {
12633
12702
  }
12634
12703
  const orgSlug = doc.secrets?.FLY_ORG_SLUG?.value?.trim() || (process.env.FLY_ORG_SLUG ?? "personal").trim();
12635
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() || "";
12636
12706
  console.log(
12637
12707
  `[preview-build] vault: ${Object.keys(buildEnv).length} secrets, mode=${buildMode}`
12638
12708
  );
@@ -12696,22 +12766,42 @@ var runPreviewBuild = async (ctx, _profile, _args) => {
12696
12766
  ["login", "registry.fly.io", "-u", "x", "--password-stdin"],
12697
12767
  { input: flyToken, cwd: ctx.cwd }
12698
12768
  );
12699
- const buildArgs = [
12700
- "build",
12701
- "-f",
12702
- "Dockerfile.preview",
12703
- "-t",
12704
- `registry.fly.io/${appName}:${tag}`
12705
- ];
12706
- if (baseImage) buildArgs.push("--build-arg", `BASE_IMAGE=${baseImage}`);
12707
- buildArgs.push(".");
12708
- await runCmd("docker", buildArgs, {
12709
- cwd: ctx.cwd,
12710
- env: { DOCKER_BUILDKIT: "1" }
12711
- });
12712
- await runCmd("docker", ["push", `registry.fly.io/${appName}:${tag}`], {
12713
- cwd: ctx.cwd
12714
- });
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
+ }
12715
12805
  const stale = await flyListMachines(appName, flyToken);
12716
12806
  for (const m of stale) {
12717
12807
  await flyDestroyMachine(appName, m.id, flyToken).catch(() => void 0);
@@ -18,7 +18,12 @@ ARG BASE_IMAGE=node:22-alpine
18
18
  FROM ${BASE_IMAGE}
19
19
  WORKDIR /app
20
20
 
21
- RUN corepack enable 2>/dev/null || true
21
+ # corepack's default pnpm on the base image can fall outside the app's
22
+ # engines.pnpm range → ERR_PNPM_UNSUPPORTED_ENGINE. Pin a current pnpm
23
+ # for repos that don't set packageManager (corepack still honors one
24
+ # when present, so this only affects the unpinned case).
25
+ RUN corepack enable 2>/dev/null || true; \
26
+ corepack prepare pnpm@10.17.0 --activate 2>/dev/null || npm i -g pnpm@10 2>/dev/null || true
22
27
 
23
28
  COPY package.json pnpm-lock.yaml* package-lock.json* yarn.lock* ./
24
29
  RUN --mount=type=cache,id=kp-pnpm-store,target=/root/.local/share/pnpm/store \
@@ -12,7 +12,12 @@ ARG BASE_IMAGE=node:22-alpine
12
12
  FROM ${BASE_IMAGE}
13
13
  WORKDIR /app
14
14
 
15
- RUN corepack enable 2>/dev/null || true
15
+ # corepack's default pnpm on the base image can fall outside the app's
16
+ # engines.pnpm range → ERR_PNPM_UNSUPPORTED_ENGINE. Pin a current pnpm
17
+ # for repos that don't set packageManager (corepack still honors one
18
+ # when present, so this only affects the unpinned case).
19
+ RUN corepack enable 2>/dev/null || true; \
20
+ corepack prepare pnpm@10.17.0 --activate 2>/dev/null || npm i -g pnpm@10 2>/dev/null || true
16
21
 
17
22
  COPY package.json pnpm-lock.yaml* package-lock.json* yarn.lock* ./
18
23
  RUN --mount=type=cache,id=kp-pnpm-store,target=/root/.local/share/pnpm/store \
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.188",
3
+ "version": "0.4.190",
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
- "scripts": {
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
+ }
@@ -77,6 +77,7 @@ jobs:
77
77
  pull-requests: write
78
78
  contents: write
79
79
  actions: read
80
+ id-token: write # OIDC: lets preview-build federate into Namespace remote builders
80
81
  steps:
81
82
  - uses: actions/checkout@v4
82
83
  with: