diff --git a/README.md b/README.md index 74e2576..5dca924 100644 --- a/README.md +++ b/README.md @@ -73,11 +73,14 @@ StackForge is local-first and review-friendly: Generated repositories include `scripts/validate.sh` as the default local verification path. It runs the repo's normal local package checks when they exist, including `release:check`, and only runs `agent-qc ready` when `agent-qc` is installed, so `agent-qc` stays optional. -The `next-app` scaffold ships an npm lockfile and an exact, reviewed Next.js -toolchain. Use `npm ci` for a reproducible install and `npm run audit` to check -the production dependency graph for high or critical advisories. The scaffold -temporarily overrides Next.js's bundled `postcss` and `sharp` versions because -the upstream range otherwise resolves releases with active advisories. +The `next-app` scaffold ships an npm lockfile, `.gitignore`, `next-env.d.ts`, +`tsconfig.json`, and an exact, reviewed Next.js toolchain. Its TypeScript +metadata is complete before the first install or build, so framework commands +do not need to rewrite the generated project. Use `npm ci` for a reproducible +install and `npm run audit` to check the production dependency graph for high +or critical advisories. The scaffold temporarily overrides Next.js's bundled +`postcss` and `sharp` versions because the upstream range otherwise resolves +releases with active advisories. `oss-cli` projects also include ReleaseBox by default: `releasebox.config.json`, reviewed/tag-gated GitHub release workflows, and package smoke scripts. The generated release path creates GitHub Releases with attached tarballs while leaving npm and Homebrew publishing disabled until explicitly enabled. diff --git a/scripts/smoke-init.sh b/scripts/smoke-init.sh index dd9dd92..5b91280 100755 --- a/scripts/smoke-init.sh +++ b/scripts/smoke-init.sh @@ -179,6 +179,9 @@ node "$repo_root/dist/index.js" init next-app web-app > next.json test -f web-app/src/app/page.tsx test -f web-app/eslint.config.mjs test -f web-app/package-lock.json +test -f web-app/.gitignore +test -f web-app/next-env.d.ts +test -f web-app/tsconfig.json node -e ' const pkg = require("./web-app/package.json"); const expected = { @@ -201,11 +204,19 @@ node -e ' ' ( cd web-app + git init -q + git add . + git -c user.name="StackForge Smoke" -c user.email="smoke@example.invalid" commit -qm "test: capture generated scaffold" npm ci --ignore-scripts npm run lint npm run build npm run audit bash scripts/validate.sh + test -z "$(git status --porcelain)" || { + echo "next-app verification modified generated scaffold files" >&2 + git status --short >&2 + exit 1 + } ) echo "smoke-init ok" diff --git a/src/index.ts b/src/index.ts index 3b4ebbf..c4781d7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -81,6 +81,9 @@ const templateScaffolds: Record = { { source: 'templates/repo-validate/validate.sh', destination: 'scripts/validate.sh' }, { destination: 'package.json', content: nextPackageJsonTemplate() }, { source: 'templates/next-app/package-lock.json', destination: 'package-lock.json', render: true }, + { destination: '.gitignore', content: nextGitignoreTemplate() }, + { destination: 'next-env.d.ts', content: nextEnvironmentDeclarationTemplate() }, + { destination: 'tsconfig.json', content: nextTypeScriptConfigTemplate() }, { destination: 'eslint.config.mjs', content: nextEslintConfigTemplate() }, { destination: 'src/app/page.tsx', content: "export default function Home() {\n return
{{PROJECT_NAME}}
;\n}\n" }, { destination: 'src/app/layout.tsx', content: "export default function RootLayout({ children }: { children: React.ReactNode }) {\n return (\n \n {children}\n \n );\n}\n" } @@ -555,6 +558,48 @@ export default defineConfig([ `; } +function nextGitignoreTemplate(): string { + return `node_modules/ +.next/ +out/ +build/ +`; +} + +function nextEnvironmentDeclarationTemplate(): string { + return `/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. +`; +} + +function nextTypeScriptConfigTemplate(): string { + return `{ + "compilerOptions": { + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "plugins": [{ "name": "next" }] + }, + "include": ["next-env.d.ts", ".next/types/**/*.ts", ".next/dev/types/**/*.ts", "**/*.ts", "**/*.tsx"], + "exclude": ["node_modules"] +} +`; +} + function pythonProjectTemplate(): string { return `[project] name = "{{PROJECT_NAME}}"