2026-06-01 16:30:29 +02:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
// Make the WASM runtime artifacts available SAME-ORIGIN to the app without a
|
2026-06-09 12:35:46 +02:00
|
|
|
// third copy: symlink standalone/public/wasm -> the synced artifact dir
|
2026-06-01 16:30:29 +02:00
|
|
|
// (tests/apps/kicad, populated by tests/scripts/setup-kicad-wasm.sh). Vite then
|
|
|
|
|
// serves them at /wasm from the app's own origin — required because KiCad WASM
|
jspi cleanup: remove the asyncify-era residue — dead code, conditionals, pipeline scaffolding, stale prose
The runtime is JSPI-only; this removes everything that still pretended
otherwise. Three exhaustive sweeps (C++/JS+build+CI/tests+docs) drove
the inventory; every deletion verified by grep closure + full gates.
Broken-right-now fixes:
- deploy-staging.yml passed the retired opt_level input — the workflow
could not even start. Removed.
- env.sh carried dead exports with a live -sASYNCIFY=1 inside
(WASM_LDFLAGS/PTHREAD_LDFLAGS, zero consumers). Removed; the
WASM_LEGACY_EXCEPTIONS rationale rewritten to the real reason.
- docker/build.sh exported PCBJAM_ASYNC_BACKEND (read nowhere). Gone.
Dead weight removed:
- binaryen submodule (nothing builds or invokes it), wasm-opt-bench
workflow + scripts/bench/, get-wasm-opt.sh, diagnostics.js (242 lines
of Asyncify-API-only code), the KICAD_PIPELINE background-postprocess
scaffolding (existed to parallelize the deleted wasm-opt phase; the
postprocess is a seconds-long node script and now runs inline),
build-monitor's dead asyncify rows, sched-context orphan build
output, dead .gitignore entries, the .jspi-assets spike dir (the two
wf-result research JSONs moved to docs/features/async/migration-evidence/).
- bindings: fiber_park.h + its 12 embind registrations (broken-if-
called under JSPI), the kicadOpenFileStart/OPEN_JOB starter route,
main_stack_runner.h + 5 includes, the always-null context-sleep weak
hook in nanosleep_yield.c.
- shim: the backend field (installed-flag idempotency instead),
noteContextWait (dead both sides), the __wxAsyncifyDump alias (+ the
WasmTool fallback and string-dump normalize branch).
- web: the emscripten-6-ignored mainScriptUrlOrBlob option in boot.ts
(gerber-demo keeps it: it loads the deployed CDN release, which
predates emscripten 6 — noted inline).
Conditionals: all 'backend === jspi' checks reduced to scheduler-
presence checks; races_quiescent re-keyed from Asyncify.state (vacuous)
to real backlog quiescence (resumeReady/mutatorQueue — NOT _windowLive,
which is the probing activation's own window by definition).
Renames (identifiers only, no file renames): ASYNC_LINK_FLAGS→
JSPI_LINK_FLAGS and Makefile ASYNC_LDFLAGS→JSPI_LDFLAGS,
kicadCollabFiberBusy→kicadCollabBusy (embind + web + tests),
collab_common.h fiber*→apply*/coroutine naming, asyncifySignatures→
wasmTrapSignatures (lists byte-identical).
Tests: the two remaining vacuous [wx-asyncify]/fiber-resume-refused
asserts re-keyed to live JSPI beacons; eeschema-load's failure message
no longer sends the developer to a deleted script; wait-beacons' dead
families/parser deleted; lane-0 legacy-glue guards removed (lane 0 is
unconstructible); the embind test.fail re-gated with the JSPI reason
(plain embind invokers cannot suspend — verified still failing);
lint-determinism now scans tests/jspi (166 files clean);
eeschema-collab local-move gated to chromium (~50% flaky on FF even
solo; pcbnew twin covers both engines).
Docs: DEBUG.md rewritten as the JSPI debugging guide; build.md
describes the single-phase build; docs/features/async/README.md
banner-marked historical and repointed at the NEW
23-jspi-runtime.md (current architecture: export census, turnstile,
libcontext ownership + refusal contract, embind call shapes, the
em-pthread service-wrapper trick, exception policy, known gaps).
Gates on the cleaned tree: test:e2e 725 passed / 0 failed (after the
quiescence-probe fix; the 3 other reds were verified contention flakes
solo-green or the documented FF gate), web 76/0, jspi 18/18 both
engines, vitest 295/295 + 17/17, all lints green, live-app census
clean.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016X9eh1s5sTx1o9Em9KBuwR
2026-08-14 09:25:32 +02:00
|
|
|
// (a COEP/cross-origin-isolated document) refuses to load its
|
2026-06-01 16:30:29 +02:00
|
|
|
// glue/wasm from a different origin.
|
|
|
|
|
//
|
|
|
|
|
// No bytes are duplicated; the link points straight at the synced dir.
|
|
|
|
|
// Override the target with WASM_SRC_DIR (absolute, or relative to cwd).
|
|
|
|
|
|
|
|
|
|
import { spawnSync } from "node:child_process";
|
|
|
|
|
import * as fs from "node:fs/promises";
|
|
|
|
|
import * as path from "node:path";
|
|
|
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
|
|
|
|
|
|
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
|
|
|
const publicDir = path.resolve(scriptDir, "../public");
|
|
|
|
|
const linkPath = path.join(publicDir, "wasm");
|
2026-06-09 12:35:46 +02:00
|
|
|
// scriptDir = web/standalone/scripts → repo root is three levels up.
|
|
|
|
|
const repoRoot = path.resolve(scriptDir, "../../..");
|
2026-06-01 16:30:29 +02:00
|
|
|
const setupScript = path.join(repoRoot, "tests/scripts/setup-kicad-wasm.sh");
|
|
|
|
|
|
|
|
|
|
const targetAbs = process.env.WASM_SRC_DIR
|
|
|
|
|
? path.resolve(process.cwd(), process.env.WASM_SRC_DIR)
|
|
|
|
|
: path.join(repoRoot, "tests/apps/kicad");
|
|
|
|
|
|
|
|
|
|
// Sync freshly-built artifacts from output/ into tests/apps/kicad before
|
|
|
|
|
// linking, so `npm run dev` always serves the latest build instead of whatever
|
|
|
|
|
// was synced last. Skipped when WASM_SRC_DIR overrides the target: the setup
|
|
|
|
|
// script only writes to tests/apps/kicad, so running it would be a no-op there
|
|
|
|
|
// (and would mislead by syncing a dir we're not even linking to).
|
|
|
|
|
// Non-fatal: a missing/empty build must not block the dev server from starting.
|
|
|
|
|
// The setup script exits non-zero when no artifacts exist anywhere; we warn and
|
|
|
|
|
// fall through to the symlink, which already degrades gracefully (see below).
|
|
|
|
|
function syncArtifacts() {
|
|
|
|
|
if (process.env.WASM_SRC_DIR) {
|
|
|
|
|
console.log("[link-wasm] WASM_SRC_DIR set — skipping output/ sync");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const res = spawnSync("bash", [setupScript], { stdio: "inherit" });
|
|
|
|
|
if (res.error) {
|
|
|
|
|
console.warn(
|
|
|
|
|
`[link-wasm] could not run setup-kicad-wasm.sh: ${res.error.message}`,
|
|
|
|
|
);
|
|
|
|
|
} else if (res.status !== 0) {
|
|
|
|
|
console.warn(
|
|
|
|
|
`[link-wasm] setup-kicad-wasm.sh exited ${res.status} — ` +
|
|
|
|
|
`serving whatever is already in ${path.relative(repoRoot, targetAbs)}`,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Relative link so it stays valid if the repo moves.
|
|
|
|
|
const targetRel = path.relative(publicDir, targetAbs);
|
|
|
|
|
|
|
|
|
|
async function statOrNull(p, { follow = true } = {}) {
|
|
|
|
|
try {
|
|
|
|
|
return follow ? await fs.stat(p) : await fs.lstat(p);
|
|
|
|
|
} catch {
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
|
syncArtifacts();
|
|
|
|
|
|
|
|
|
|
await fs.mkdir(publicDir, { recursive: true });
|
|
|
|
|
|
|
|
|
|
const link = await statOrNull(linkPath, { follow: false });
|
|
|
|
|
if (link?.isSymbolicLink()) {
|
|
|
|
|
const current = await fs.readlink(linkPath);
|
|
|
|
|
if (path.resolve(publicDir, current) === targetAbs) {
|
|
|
|
|
// already correct
|
|
|
|
|
} else {
|
|
|
|
|
await fs.rm(linkPath);
|
|
|
|
|
await fs.symlink(targetRel, linkPath, "dir");
|
|
|
|
|
}
|
|
|
|
|
} else if (link) {
|
|
|
|
|
// A real dir/file (e.g. an earlier copy) — remove and link.
|
|
|
|
|
await fs.rm(linkPath, { recursive: true, force: true });
|
|
|
|
|
await fs.symlink(targetRel, linkPath, "dir");
|
|
|
|
|
} else {
|
|
|
|
|
await fs.symlink(targetRel, linkPath, "dir");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const target = await statOrNull(targetAbs);
|
|
|
|
|
if (!target?.isDirectory()) {
|
|
|
|
|
console.warn(
|
|
|
|
|
`[link-wasm] target not found: ${targetAbs}\n` +
|
|
|
|
|
`[link-wasm] run tests/scripts/setup-kicad-wasm.sh (or set WASM_SRC_DIR). ` +
|
|
|
|
|
`App will run but tools won't load.`,
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
const hasWx = await statOrNull(path.join(targetAbs, "wx.js"));
|
|
|
|
|
console.log(
|
|
|
|
|
`[link-wasm] public/wasm -> ${path.relative(repoRoot, targetAbs)}` +
|
|
|
|
|
(hasWx ? "" : " (warning: wx.js missing in target)"),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
main().catch((err) => {
|
|
|
|
|
console.error("[link-wasm]", err);
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|