* fix: resolve symlink paths in standalone BFS package copy (#724)
When resolvePackageJsonPath finds a package via the lookup-paths
fallback, the returned path may be a symlink (e.g., under a hoisted
node_modules/ directory). Calling createRequire() on a symlink
path causes Node module resolution to miss transitive dependencies
because it walks up from the symlink ancestor directories rather
than the real (e.g., .pnpm/) path.
Fix: call fs.realpathSync() on the resolved package.json path
before using it for createRequire() and readPackageJson().
Also adds E2E test coverage for the standalone output mode.
* fix: address review feedback
Add standalone-output to CI E2E matrix, rename server header test
to reflect what it actually asserts, fix unused req parameter.
Bots throw "max_tokens not supported, use max_completion_tokens" on
1.4.6 with gpt-5.x reasoning models. opencode 1.4.6 predates the
cf-ai-gateway plugin's chat.params hook (PR #22864, landed in 1.4.7),
which strips maxOutputTokens for OpenAI reasoning models so the
@ai-sdk/openai-compatible default no longer leaks the rejected field.
The earlier ProviderInitError on 1.14.x was a separate regression in
opencode's npm install path: the major bump introduced loadOptions(dir)
via @npmcli/config inside Npm.add, which fails on CI runners and bubbles
up as InstallFailedError, then gets re-wrapped at provider.ts:1522 as
ProviderInitError with the original cause swallowed by the session
error path. Other Cloudflare repos (workers-sdk, workerd, kumo) hit the
same regression on anthropic and pinned 1.4.6 / 1.2.27 to dodge it.
1.4.11 is the last 1.4.x release: it has the chat.params max_tokens
patch and predates the loadOptions install regression. Same
ai-gateway-provider 3.1.2, same @ai-sdk pins as 1.4.6, so the install
path stays the known-good arborist.reify call shape that works for
workers-sdk + anthropic on 1.4.6.
Verified locally with opencode 1.14.25 + cf-ai-gateway/openai/gpt-5.4 +
fake creds: empty-cache short-circuit and loadOptions both reproduce
the silent ProviderInitError. 1.4.11 lacks both code paths.
Every bonk and bigbonk run since opencode 1.14.25 throws
UnknownError: ProviderInitError during cf-ai-gateway SDK init,
regardless of model. Verified across gpt-5.5 (#898), gpt-5.4 (#900),
and the throw fires before any per-model code path runs.
workers-sdk hit the same regression and pinned opencode_version to
1.4.6 with an inline comment naming ProviderInitError as the cause.
Several other Cloudflare repos pin 1.2.27 / 1.4.6 for the same
reason. vinext is the only Cloudflare repo running OAI through
cf-ai-gateway, so the OAI-specific path stayed unobserved until #898
re-tried it on 1.14.25.
Pinning to 1.4.6 here reuses workers-sdk's known-good version. The
gpt-5.4 model from #900 stays; gpt-5.4 predates 1.4.6's bundled
snapshot by over a month, so registry resolution is fine.
bonk and bigbonk currently throw ProviderInitError on every invocation
after the gpt-5.5 switch in #898. The lookup-side regression that #899
patched was masked by the opencode bump (1.14.22 -> 1.14.25) but a
second failure now surfaces during SDK init for cloudflare-ai-gateway.
opencode swallows the underlying cause, and the gpt-5.5 path through
ai-gateway-provider has no working precedent in this repo, so iterating
on it would block PR review indefinitely.
Roll the model back to gpt-5.4, which has a known-good path through
opencode + ai-gateway-provider + Cloudflare AI Gateway, and remove the
opencode.json workaround introduced in #899. Reasoning effort stays at
"xhigh" per James's preference; opencode will fall back to its default
effort if gpt-5.4 doesn't accept it.
Once gpt-5.5 SDK init is fixed upstream (opencode + ai-gateway-provider
+ models.dev cloudflare-ai-gateway entry), we can roll forward again.
* ci(bonk): switch bonk workflow to GPT-5.5 xhigh variant
Updates the bonk workflow to use cloudflare-ai-gateway/openai/gpt-5.5
with reasoning effort variant xhigh, replacing the previous
claude-opus-4-7 model.
https://claude.ai/code/session_012n6RFuqfQGQY7AaayqLcaG
* ci(bonk): extend GPT-5.5 xhigh switch to bigbonk, agent defs, and docs
- bigbonk workflow: cloudflare-ai-gateway/openai/gpt-5.5 with variant xhigh (was claude-opus-4-7 + max)
- viguy and reviewer OpenCode agent definitions: openai/gpt-5.5 (was anthropic/claude-opus-4-7)
- CONTRIBUTING.md: update recommended setup and BigBonk description to GPT-5.5 xhigh
The Next.js tracker workflow and agent are intentionally left on Claude
Opus 4.7.
https://claude.ai/code/session_012n6RFuqfQGQY7AaayqLcaG
---------
Co-authored-by: Claude <noreply@anthropic.com>
* chore: upgrade workflows from claude-opus-4-6 to claude-opus-4-7
Update model references in bonk, bigbonk, and nextjs-tracker workflows
to use the latest Opus 4.7 model via the Cloudflare AI Gateway.
https://claude.ai/code/session_018pEfYehfR4YDA1Ekmu1vn3
* chore: upgrade opencode agents from claude-opus-4-6 to claude-opus-4-7
Update model references in reviewer, viguy, and nextjs-tracker agent
configs to use the latest Opus 4.7 model.
https://claude.ai/code/session_018pEfYehfR4YDA1Ekmu1vn3
---------
Co-authored-by: Claude <noreply@anthropic.com>
* chore: harden CI supply chain
- Pin voidzero-dev/setup-vp to commit SHA across all workflows
- Pin create-next-app and pkg-pr-new to exact versions
* pull setup-vp into setup action
---------
Co-authored-by: James <james@eli.cx>
* fix: security audit findings from issue #741
CI shell injection (high):
- publish.yml: use env var for inputs.bump in case statement
- nextjs-tracker.yml: use env vars for since_hours and dry_run inputs
- nextjs-tracker.yml: use env var in Skip step echo
Test file false positive (critical flag):
- tests/vite-hmr-websocket.test.ts: add gitleaks:allow for RFC 6455
example WebSocket nonce (dGhlIHNhbXBsZSBub25jZQ==)
innerHTML / XSS (high):
- packages/vinext/src/shims/script.tsx: add security comment documenting
that dangerouslySetInnerHTML is developer-supplied inline script only
- packages/vinext/src/shims/head.ts: document tag is bounded to
RAW_CONTENT_TAGS (script/style), not user input
dangerouslySetInnerHTML in example (medium):
- examples/hackernews/components/comment.jsx: sanitize HN API HTML
with DOMPurify before rendering
- examples/hackernews/package.json: add dompurify dependency
- pnpm-workspace.yaml: add dompurify and @types/dompurify to catalog
Non-literal RegExp (medium): documented as internal config values only,
no user input reaches any of the 6 flagged patterns. See safeRegExp()
in config-matchers.ts which already enforces ReDoS protection.
Deprecation cleanup:
- examples/hackernews/tsconfig.json: remove deprecated baseUrl option
(moduleResolution: bundler handles resolution; all imports are relative)
- examples/hackernews/tsconfig.json: add noEmit: true to prevent TypeScript
from attempting to write over existing .js files in lib/
- examples/hackernews/package.json: add missing @cloudflare/workers-types
devDependency (was referenced in tsconfig types but not installed)
* fix: address bonk review comments
- Switch dompurify → isomorphic-dompurify so sanitize() works during
SSR (DOMPurify is a no-op without window/document; isomorphic-dompurify
bundles jsdom for server-side use)
- Revert package.json whitespace to 2-space indentation (was inadvertently
changed to 4-space, creating noise in the diff)
- Replace dompurify + @types/dompurify catalog entries with
isomorphic-dompurify (ships its own types, no separate @types needed)
- Add missing trailing newline to tsconfig.json
* fix: address bonk review comments on PR #769
- Switch from isomorphic-dompurify to sanitize-html, and move
sanitization to the server-side data boundary (lib/get-comments.js).
isomorphic-dompurify depends on jsdom which is Node.js-specific and
does not work in the Cloudflare Workers runtime. sanitize-html is
pure-JS (htmlparser2-based) with no DOM dependency and works in both
Workers and Node.js. Sanitizing once at the data boundary means both
the SSR'd initial HTML response and client re-renders receive safe text.
- Remove the DOMPurify import from comment.jsx; the client component no
longer needs to sanitize since text is already clean when passed as a prop.
- Replace isomorphic-dompurify with sanitize-html in the workspace catalog.
- Remove inert eslint-disable-next-line comment from script.tsx; the project
uses oxlint which ignores ESLint-specific inline suppression directives.
---------
Co-authored-by: Luke Percy <lpercyagile@gmail.com>
* test: add static export E2E tests (#564)
Add Playwright E2E tests for `output: "export"` static builds covering
both App Router and Pages Router. Includes a lightweight static file
server with path traversal protection, proper error handling, and
startup validation.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Update tests/e2e/static-export/serve-static.mjs
Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: ask-bonk[bot] <249159057+ask-bonk[bot]@users.noreply.github.com>
The agent kept launching a Task subagent to "explore the vinext codebase
structure" despite instructions not to, consuming the entire 30-minute
timeout. The task permission deny in the agent config was not effective.
Fix: embed the commits JSON directly into the prompt so the agent has
all data immediately and no reason to explore. Also add explicit
"do not explore, do not launch subagents" at the end of the prompt.
The ask-bonk action doesn't support a prompt_file input. The prompt was
silently ignored, causing the scheduled run to fail with 'PROMPT input
is required'. Set the prompt as a multiline step output and reference it
via the prompt input instead.
Daily scheduled job that scans Next.js canary commits, uses an AI agent
to classify relevance to vinext, and opens labeled tracking issues for
anything that matters. Supports a dry-run mode for validation.
* chore: bump pnpm to 10.32.1 and enable vitest agent reporter
* chore: upgrade GitHub Actions to Node 24 compatible versions
* perf: re-land unit/integration split and add CI sharding
- Restore unit/integration vitest project split (lost in vp migration)
- vitest 4 supports fileParallelism per-project (was global-only in v3),
so unit tests now run in parallel (~11s) while integration stays serial
- Add 3-shard matrix for integration tests in CI, cutting wall time from
~4.5min to ~1.5min
- Move kv-cache-handler to integration to avoid flakiness under parallelism
* chore: remove unused deploy-preview slash command workflow
* ci: add sentinel job for stable branch protection rule
* feat: full next/compat/router support and fix check scanner for shimmed modules
- Export NextRouter interface from shims/router.ts so compat-router.ts can use it
- Add NextRouter | null return type to useRouter() in shims/compat-router.ts
- Add next/compat/router, next/form, next/web-vitals, next/constants to IMPORT_SUPPORT in check.ts so vinext check no longer flags them as unsupported
- Add integration fixture pages and components for next/compat/router in both pages-basic and app-basic fixtures
- Add integration tests in tests/pages-router.test.ts and tests/nextjs-compat/hooks.test.ts
- Add unit tests in tests/check.test.ts covering all four newly-registered imports
* test: update entry-templates snapshots for compat-router-test fixture page
* remove type assertion
* fix: add declare module for next/compat/router to fixture next-shims.d.ts files
* fix: add declare module for next/compat/router to internal next-shims.d.ts
* pin to vp setup 1.0.0
The version bump step modifies package.json without committing, leaving
the working tree dirty. pnpm publish enforces git-checks by default and
refuses to publish. Pass --no-git-checks before the -- separator so
pnpm skips the check while --provenance still reaches npm.
* chore: migrate to vite plus
* Disable typeAware and typeCheck
* Update CI
* Fix CI
* Fix test
* Clean
* Run test with vp
* Try revert
* react: false In test
* Fix test
* Revert "Try revert"
This reverts commit 009da10473.
* Update
* Update
* Try revert ci changes
* revert
* Run vp migrate
* Disable typeAware and typeCheck for now
* Better resolve for test
* Use vp dev instead of vite
* Update expect
* Fix NormalizeManifestModuleId
* Try increase timeout
* Update to use vp
* Try new check
* Bring back npx vp
* Migrate CI
* Make next-intl resolvable
* Update
* Update
* Update
* fix: tag GitHub @usernames in release notes, publish release directly
* fix: move contributor mentions to end-only Contributors section
* fix: trim SHA to 7 chars in commits.txt sent to AI
* add oxfmt formatter: config, scripts, CI, editor setup, docs
* rebuild lockfile
* fix: add Format to required checks list, remove dead ignore pattern
* run fmt
* add format to agents.md again
* refactor(ci): extract composite actions and improve workflow hygiene
- Add composite actions: setup-node-pnpm, build-vinext, deploy-example, comment-preview-urls
- Cache Playwright browsers in CI to avoid ~150MB download per E2E run
- Add concurrency group to deploy-examples.yml to prevent deploy pileup
- Replace inline CJS node script in create-next-app job with portable bash
- Convert ecosystem-run.yml inline Node scripts from CJS require() to ESM
- Apply composite actions across all workflows to eliminate repeated boilerplate
* refactor(ci): revert to inline steps, keep only setup-node-pnpm composite action
Remove the build-vinext, deploy-example, and comment-preview-urls composite
actions and inline their steps back into each workflow. Keep setup-node-pnpm
as the one reusable action (pnpm install + node setup). Retain all other
improvements from the previous commit: concurrency groups, Playwright browser
cache, bash-based dev-server check, ESM node scripts in ecosystem-run.
* refactor(ci): use setup-node-pnpm composite action consistently
Every workflow that does pnpm/node setup + install now uses the
setup-node-pnpm composite action instead of the inline 3-step triplet.
Added optional registry-url input to support publish.yml's npm auth.
Exceptions (intentionally kept inline):
- bonk.yml / bigbonk.yml: issue_comment trigger, GHAS constraint
- tip.yml notify-on-failure: node-only, no pnpm install needed
* Skip deploy previews for fork PRs that lack Cloudflare secrets
Fork PRs don't have access to repository secrets (CLOUDFLARE_API_TOKEN,
CLOUDFLARE_ACCOUNT_ID), so deploy/smoke-test/comment steps always fail.
Add a fork detection condition to skip these steps gracefully. The build
steps still run, so example builds are still validated for fork PRs.
* Run safe CI for external contributors, add /deploy-preview slash command
Switch ci.yml from pull_request to pull_request_target so lint, typecheck,
vitest, and e2e run automatically for fork PRs without needing approval.
No secrets are used, so this is safe with untrusted code.
Add a /deploy-preview slash command workflow that lets maintainers trigger
deploy previews on fork PRs. Gated by author_association (org members,
collaborators, repo owners only).
Cloudflare employees who push branches to the main repo continue to get
automatic deploy previews via the existing deploy-examples.yml workflow.
* Revert ci.yml to pull_request, skip deploy-examples for fork PRs
Simpler approach: keep ci.yml on pull_request (first-time contributor
approval is fine, avoids cache poisoning concern with pull_request_target).
The actual fix: add a job-level if condition to deploy-examples.yml so the
entire workflow is skipped for fork PRs. This prevents the noisy
failed/skipped deploy checks on external contributor PRs.
Update docs in AGENTS.md and README.md to reflect the approach.
* fix: add scope constraint to Bonk agent prompts (#161)
* Apply suggestion from @elithrar
* Apply suggestion from @elithrar
* fix: reference $ISSUE_NUMBER/$PR_NUMBER env vars as ground truth in scope constraint