feat(config): support output.distPath for the artifact build root - #296
Conversation
The artifact output was hardcoded to <root>/dist with only the per-invocation --output flag as an override. defineConfig now accepts output.distPath (Rsbuild/Rslib naming, string shorthand only): CLI --output still wins, the default stays dist, and the configured value flows from one PreparedProject source of truth into build/prepack, inspect, source-snapshot exclusion, the dev watcher ignore set, and the Workbench host-discovery doctor drift source that previously pinned <root>/dist. Config values must be project-root-contained relative POSIX paths; malformed shapes, root escapes, and reserved namespaces report AB4707-AB4709. Per-asset distPath subdirs, filename templates, assetPrefix, and cleanDistPath are deliberately deferred: host-pack internals are framework-owned and content-addressed, so only WHERE the artifact root lives is configurable.
🦋 Changeset detectedLatest commit: dd6b466 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: dd6b466933
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (segments.some((segment) => segment.length === 0 || segment === '.' || segment === '..')) { | ||
| return 'path'; | ||
| } | ||
| return reservedArtifactDistPathSegments.has(segments[0]!) ? 'reserved' : undefined; |
There was a problem hiding this comment.
Reject reserved output names case-insensitively
On case-insensitive filesystems, including Windows and typical macOS installations, values such as SRC, .GIT, or Node_Modules refer to the reserved directories but pass this exact-case membership check. A subsequent build publishes by replacing the resolved output directory, so output: { distPath: 'SRC' } can replace and delete the project's actual src tree. Normalize the first segment for platforms with case-insensitive path semantics, or otherwise compare it against the existing filesystem entry before accepting it.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in a45992e: artifactDistPathIssue now lowercases the first path segment before reserved-name lookup, with regressions for mixed/uppercase src, .git, node_modules, and .agent-bundle.
| artifact manifest. Unlike machine-local Rsbuild config, the hashed, portable | ||
| release-identity config rejects absolute paths; use the per-invocation CLI | ||
| flag when an absolute path is required. |
There was a problem hiding this comment.
Do not advertise unsupported absolute CLI outputs
When a user follows this new guidance and passes an absolute path outside the project, build() includes that path in ProjectService.outputRoots, whose resolveOutputRoots rejects anything outside the project root and returns AB7002 before the artifact build runs. Therefore the CLI cannot currently serve as the documented escape hatch for absolute output locations; either allow external CLI output roots during preparation or remove this promise (which also appears in AgentBundleOutputConfig).
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 3c2240169. The framework docs and AgentBundleOutputConfig TSDoc now state that --output only overrides the relative artifact root and remains subject to project-root containment; rejection behavior is unchanged.
Summary
defineConfiggains an optionaloutput: { distPath?: string }(Rsbuild/Rslib naming; string shorthand only). Precedence: CLI--output> configoutput.distPath>dist. Existing projects change nothing — projects that had to pass--output artifactbecause of the AB4706 package-build overlap can now declare it in config.PreparedProject.artifactDistPath(ProjectService resolves config-or-default afterloadConfig, merging the directory intooutputRootsthe same way the eval runs dir already was). Consumers wired:build()/prepack()resolution,inspect(output.distPathon the ready result), source-snapshot exclusion for every command, the dev watcher ignore set (initial + live on re-prepare), and the Workbench host-discovery doctor driftbundleSourcethat previously hardcoded<root>/dist(feat(workbench): read-only host discovery page over the install doctor (#105 stage 4) #285 wiring) and was already wrong for--output artifactprojects..././empty-segment paths, AB4709 reserved first segments (.agent-bundle,.git,node_modules,src). Registered in docs/diagnostics.md.distPathsubdirs,output.filenametemplates,assetPrefix,cleanDistPath— host-pack internals (<target>/skills|mcp|scripts|assets/...) are framework-owned and content-addressed through the artifact manifest, so there are no user-meaningful naming knobs to expose. The config decides WHERE the artifact root lives, never its layout.Test plan
PreparedProject.artifactDistPathincl. malformed fallback + snapshot exclusion of a configuredbuild/artifacttreeartifact-outproject builds + validates + dev-serves; host-discoverybundleSourcereflects configured path (and/distdefault); watcher exclusions initial + mid-session config change