Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .github/workflows/build-snapshot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ jobs:
libreoffice --version
test -f /home/node/cheatcode-next-template/pnpm-lock.yaml
test -f /home/node/cheatcode-expo-template/pnpm-lock.yaml
test -f /home/node/cheatcode-next-template/next.config.ts
test ! -e /home/node/cheatcode-next-template/node_modules
test ! -e /home/node/cheatcode-expo-template/node_modules
test -x /home/node/.cheatcode/app-runtimes/next/node_modules/.bin/next
test -x /home/node/.cheatcode/app-runtimes/expo/node_modules/.bin/expo
NODE_PATH=/home/node/.cheatcode/app-runtimes/next/node_modules node -e "require.resolve(\"next\");require.resolve(\"react\");require.resolve(\"react-dom\")"
NODE_PATH=/home/node/.cheatcode/app-runtimes/expo/node_modules node -e "require.resolve(\"expo\");require.resolve(\"react-native-web\");require.resolve(\"@expo/metro-runtime\")"
test -f /home/node/.cheatcode/default-skills/browser-use/SKILL.md
test -f /home/node/.cheatcode/default-skills/pptx/SKILL.md
test -f /home/node/.cheatcode/default-skills/pptx/scripts/thumbnail.py
Expand Down
20 changes: 14 additions & 6 deletions infra/containers/sandbox/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -208,9 +208,12 @@ COPY --chown=node:node app-templates/ /home/node/.cheatcode-template-manifests/
COPY --chown=node:node app-generators/ /home/node/.cheatcode-app-generators/

# The generators provide source files only. Reviewed manifests and lockfiles are
# copied over them, then fetched into the node user's pnpm store so project creation
# can install the exact dependency graph offline. The Expo template artifact itself
# is pinned: create-expo-app's mutable "default" alias is intentionally not used.
# copied over them, then the exact dependency graph is installed into immutable,
# sandbox-local runtimes. Persistent /workspace is Daytona object-store FUSE: it is
# the right home for user source, but copying dependency trees there is both slow and
# non-atomic. The source-only templates stay separate so project creation copies only
# editable files. The Expo template artifact itself is pinned: create-expo-app's
# mutable "default" alias is intentionally not used.
ARG EXPO_TEMPLATE_VERSION=57.0.6
ARG EXPO_TEMPLATE_SHA256=4c2a276f05db27f4a4dfaa326123e72be33d7ad6878fdd46b8df7eb3376def3b

Expand All @@ -222,13 +225,16 @@ RUN set -eux; \
cp /home/node/.cheatcode-template-manifests/next/package.json /home/node/cheatcode-next-template/package.json; \
cp /home/node/.cheatcode-template-manifests/next/pnpm-lock.yaml /home/node/cheatcode-next-template/pnpm-lock.yaml; \
cp /home/node/.cheatcode-template-manifests/next/pnpm-workspace.yaml /home/node/cheatcode-next-template/pnpm-workspace.yaml; \
cp /home/node/.cheatcode-template-manifests/next/next.config.ts /home/node/cheatcode-next-template/next.config.ts; \
rm -rf \
/home/node/cheatcode-next-template/.next \
/home/node/cheatcode-next-template/node_modules \
/home/node/cheatcode-next-template/AGENTS.md \
/home/node/cheatcode-next-template/CLAUDE.md; \
cd /home/node/cheatcode-next-template; \
pnpm fetch --frozen-lockfile; \
mkdir -p /home/node/.cheatcode/app-runtimes; \
cp -a /home/node/cheatcode-next-template /home/node/.cheatcode/app-runtimes/next; \
cd /home/node/.cheatcode/app-runtimes/next; \
pnpm install --frozen-lockfile; \
cd /workspace; \
curl -fsSL \
"https://registry.npmjs.org/expo-template-default/-/expo-template-default-${EXPO_TEMPLATE_VERSION}.tgz" \
Expand All @@ -246,7 +252,9 @@ RUN set -eux; \
cd /home/node/cheatcode-expo-template; \
node -e 'const fs=require("node:fs");const j=JSON.parse(fs.readFileSync("app.json","utf8"));j.expo??={};j.expo.name="cheatcode-expo-template";j.expo.slug="cheatcode-expo-template";j.expo.web={...(j.expo.web??{}),bundler:"metro",output:"single"};fs.writeFileSync("app.json",JSON.stringify(j,null,2)+"\n")'; \
rm -rf .git .expo node_modules package-lock.json AGENTS.md CLAUDE.md .claude; \
pnpm fetch --frozen-lockfile; \
cp -a /home/node/cheatcode-expo-template /home/node/.cheatcode/app-runtimes/expo; \
cd /home/node/.cheatcode/app-runtimes/expo; \
pnpm install --frozen-lockfile; \
cd /workspace; \
rm -rf \
/tmp/expo-template-default.tgz \
Expand Down
8 changes: 6 additions & 2 deletions infra/containers/sandbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,12 @@ the image build. Document-runtime versions are owned by its reviewed manifest an
they are intentionally absent from the Worker workspace catalog. Its `uuid` override
keeps ExcelJS on the patched UUID implementation while preserving the public CommonJS
`v4` API that ExcelJS consumes. The Next and Expo scaffolds likewise use reviewed manifests and
pnpm locks under `app-templates/`. Their locked packages are prefetched into the image
so normal project creation can install offline. Expo uses an exact
pnpm locks under `app-templates/`. Their locked packages are installed into immutable
sandbox-local runtimes in the image. Project creation copies only source and config to
the persistent Daytona volume; dependency trees and generated compiler caches stay on
the sandbox's local filesystem, avoiding slow, partial writes to object-store FUSE.
Additional dependencies use a project-scoped local modules directory and can be
restored from the reviewed package store after a sandbox replacement. Expo uses an exact
`expo-template-default` tarball with a reviewed SHA-256 rather than the mutable
`default` alias. These locks prevent a snapshot rebuild from resolving a different
dependency tree while the application source stays unchanged.
Expand Down
9 changes: 9 additions & 0 deletions infra/containers/sandbox/app-templates/next/next.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
// User source is persistent object-store FUSE; generated compiler output belongs
// on the sandbox's fast local disk. The managed preview owns this relative path.
distDir: process.env["CHEATCODE_NEXT_DIST_DIR"] ?? ".next",
};

export default nextConfig;
2 changes: 2 additions & 0 deletions knip.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
// `cloudflare:workers` and `cloudflare:workflows` are platform modules, not
// installable package dependencies. Knip cannot infer either edge.
"ignoreDependencies": ["@cheatcode/tsconfig", "cloudflare"],
// Copied into the generated Next scaffold by the sandbox Dockerfile.
"ignore": ["infra/containers/sandbox/app-templates/next/next.config.ts"],
"includeEntryExports": true,
"workspaces": {
".": {
Expand Down