From fa5a3ef3fccd1162471a40c46593d138880142ca Mon Sep 17 00:00:00 2001 From: kjgbot Date: Sat, 5 Sep 2026 11:06:58 +0200 Subject: [PATCH 1/2] build(sdk): route npm test through scripts/test.sh Split out of #165, which bundled this with a wholesale revert of the CI workflow. The workflow half restored `ops/cargo.sh` for the kernel test step (that wrapper redirects RUSTUP_HOME to an empty dir on a runner, so rustup cannot choose a toolchain) and dropped the analyzer-skip env, i.e. it reverted #153, #154 and #159 together. Only the sdk tooling is carried here; `.github/` is byte-identical to main. scripts/test.sh runs the same chain the inline `test` script did, in the same order, with `set -eu` for the fail-fast the `&&` chain gave. The new behaviour is the EXIT trap, which prunes `.map` and `.d.ts` from sdk/dist afterward. CI is unaffected either way: the workflow runs the expanded chain minus test:prep, not `npm test`. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 --- sdk/package.json | 2 +- sdk/scripts/prune-test-build.mjs | 24 ++++++++++++++++++++++++ sdk/scripts/test.sh | 10 ++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 sdk/scripts/prune-test-build.mjs create mode 100644 sdk/scripts/test.sh diff --git a/sdk/package.json b/sdk/package.json index bd4928809..5c465c8e1 100644 --- a/sdk/package.json +++ b/sdk/package.json @@ -25,7 +25,7 @@ "typecheck": "tsc --noEmit && tsc -p tsconfig.type-tests.json", "typecheck:tests": "tsc -p tsconfig.tests.json", "test:prep": "( cd ../kernel && sh ../ops/cargo.sh build ) && ( [ ! -d ../testdata/preflight ] || find ../testdata/preflight -name '*-cli' -type f -exec chmod +x {} + )", - "test": "npm run test:prep && npm run typecheck && npm run build && npm run typecheck:tests && vitest run", + "test": "sh scripts/test.sh", "test:watch": "vitest" }, "license": "UNLICENSED", diff --git a/sdk/scripts/prune-test-build.mjs b/sdk/scripts/prune-test-build.mjs new file mode 100644 index 000000000..6f96d68d1 --- /dev/null +++ b/sdk/scripts/prune-test-build.mjs @@ -0,0 +1,24 @@ +import { readdir, rm } from "node:fs/promises"; +import { resolve } from "node:path"; + +const generatedDirectories = [resolve(import.meta.dirname, "../dist")]; + +for (const directory of generatedDirectories) { + let entries; + try { + entries = await readdir(directory, { recursive: true, withFileTypes: true }); + } catch (error) { + if (error.code === "ENOENT") continue; + throw error; + } + + await Promise.all( + entries + .filter( + (entry) => + entry.isFile() && + (entry.name.endsWith(".map") || entry.name.endsWith(".d.ts")), + ) + .map((entry) => rm(resolve(entry.parentPath, entry.name))), + ); +} diff --git a/sdk/scripts/test.sh b/sdk/scripts/test.sh new file mode 100644 index 000000000..e2b96de5c --- /dev/null +++ b/sdk/scripts/test.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -eu + +trap 'node scripts/prune-test-build.mjs' EXIT + +npm run test:prep +npm run typecheck +npm run build +npm run typecheck:tests +vitest run From 3e7ee755623e7423f8955be7ecf98684947ca806 Mon Sep 17 00:00:00 2001 From: kjgbot Date: Sat, 5 Sep 2026 12:57:28 +0200 Subject: [PATCH 2/2] build(sdk): prune only source maps, not declaration files Resolves the open question I raised on this PR rather than merging past it. `package.json` declares `"types": "./dist/index.d.ts"`, and the script deleted every `.d.ts` under `dist` -- so `npm test` left the package's declared type entry pointing at a file it had just removed. Nothing breaks today: every current in-repo consumer imports `.js` -- `ops/probes/**`, `workflows/drive.yaml:394`, `workflows/drive-cloud.yaml:247` and `testdata/backlog-picker.flow.yaml:18` all load `sdk/dist/*.js` -- and `surface` does not depend on the sdk. But the next TypeScript consumer would meet a failure whose cause is "someone ran the tests", and the space this buys is not worth that. The file count that actually drives the sandbox problem is `kernel/target/debug` at ~4900 files, per ops/cargo.sh's own measurements; `dist` declarations are noise beside it. Source maps are still pruned, which is the part with no such cost. An earlier revision of this message claimed `ops/probes/**` were the only consumers. The history lens showed that was false; the conclusion was unaffected, since all of them import `.js`, but the claim was not. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01FtQSAcGDta5VH9xiZFT4sR Session-Id: c228933d-4f94-4d83-9a9a-daf3c83b94f1 --- sdk/scripts/prune-test-build.mjs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/sdk/scripts/prune-test-build.mjs b/sdk/scripts/prune-test-build.mjs index 6f96d68d1..c4d97ba40 100644 --- a/sdk/scripts/prune-test-build.mjs +++ b/sdk/scripts/prune-test-build.mjs @@ -1,3 +1,17 @@ +// Drop the build outputs a test run does not need, to keep the propagated +// tree small in a cloud sandbox. +// +// Source maps only. Declaration files are deliberately NOT pruned: package.json +// declares `"types": "./dist/index.d.ts"`, so deleting them would leave the +// package's own declared type entry pointing at a file that `npm test` had just +// removed. Nothing in this repo breaks today -- every current in-repo consumer +// imports `.js` (`ops/probes/**`, `workflows/drive.yaml`, +// `workflows/drive-cloud.yaml`, `testdata/backlog-picker.flow.yaml`), and +// `surface` does not depend on the sdk -- but the next TypeScript consumer +// would hit a failure whose cause is "someone ran the tests", which is not a +// cost worth paying for the space. The file +// count that actually matters is `kernel/target/debug` at ~4900 files (see +// ops/cargo.sh); `dist` declarations are noise beside it. import { readdir, rm } from "node:fs/promises"; import { resolve } from "node:path"; @@ -16,8 +30,7 @@ for (const directory of generatedDirectories) { entries .filter( (entry) => - entry.isFile() && - (entry.name.endsWith(".map") || entry.name.endsWith(".d.ts")), + entry.isFile() && entry.name.endsWith(".map"), ) .map((entry) => rm(resolve(entry.parentPath, entry.name))), );