From e998aca6331d885f8ade25b5050fba21cfceda89 Mon Sep 17 00:00:00 2001 From: Swift Date: Fri, 16 Oct 2026 09:08:06 -0400 Subject: [PATCH] fix: install Mad Libs from a symlinked package path npm ci fails with "Missing: @ from lock file" when --prefix is a path through a symlink, as a demo station under macOS's /tmp is. Resolve the package directory with pwd -P, and run the install test through a symlink so CI covers it. --- challenges/vibe-coding-mad-libs/install | 3 ++- test/vibe-coding-mad-libs.test.mjs | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/challenges/vibe-coding-mad-libs/install b/challenges/vibe-coding-mad-libs/install index d95b125..2a6365a 100755 --- a/challenges/vibe-coding-mad-libs/install +++ b/challenges/vibe-coding-mad-libs/install @@ -3,5 +3,6 @@ # versions boothstrap's Pi uses, into this package's node_modules. set -eu -package_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd) +# pwd -P resolves symlinks: npm ci fails on a --prefix that isn't a real path. +package_dir=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) npm ci --ignore-scripts --no-audit --no-fund --prefix "$package_dir" diff --git a/test/vibe-coding-mad-libs.test.mjs b/test/vibe-coding-mad-libs.test.mjs index e816196..7617eaa 100644 --- a/test/vibe-coding-mad-libs.test.mjs +++ b/test/vibe-coding-mad-libs.test.mjs @@ -4,7 +4,7 @@ import assert from 'node:assert/strict' import { spawn } from 'node:child_process' -import { cp, link, mkdtemp, readFile, rm, stat, writeFile } from 'node:fs/promises' +import { cp, link, mkdtemp, readFile, rm, stat, symlink, writeFile } from 'node:fs/promises' import { createServer, get } from 'node:http' import { tmpdir } from 'node:os' import path from 'node:path' @@ -211,10 +211,13 @@ for (const { name, text, finished } of finishedPromptCases) { }) } -test('loads the extension under the pinned Pi packages after install', { timeout: installTimeoutMilliseconds + 60_000 }, async (context) => { +test('loads the extension under the pinned Pi packages after install through a symlink', { timeout: installTimeoutMilliseconds + 60_000 }, async (context) => { const installedPackage = path.join(await makeTemporaryDirectory(context), 'package') await cp(packageDirectory, installedPackage, { recursive: true, filter: (source) => path.basename(source) !== 'node_modules' }) - const installed = await runExecutable(path.join(installedPackage, 'install'), [], { timeout: installTimeoutMilliseconds }) + // A station can reach its package through a symlink, as macOS's /tmp is one. + const linkedPackage = path.join(await makeTemporaryDirectory(context), 'linked-package') + await symlink(installedPackage, linkedPackage) + const installed = await runExecutable(path.join(linkedPackage, 'install'), [], { timeout: installTimeoutMilliseconds }) assert.equal(installed.code, 0, installed.stderr) const projectDirectory = await makeTemporaryDirectory(context) const agentDirectory = await makeTemporaryDirectory(context)