Skip to content

fix(package): keep the generated installer's artifact URL statically analyzable in packed consumers (#252) - #288

Merged
ScriptedAlchemy merged 1 commit into
mainfrom
feat/252-packed-consumer-installer-fix
Sep 2, 2026
Merged

fix(package): keep the generated installer's artifact URL statically analyzable in packed consumers (#252)#288
ScriptedAlchemy merged 1 commit into
mainfrom
feat/252-packed-consumer-installer-fix

Conversation

@ScriptedAlchemy

Copy link
Copy Markdown
Owner

Summary

Follow-up fix to #281, caught while wiring #252's release lane: in a packed consumer (a plugin project whose node_modules carries agent-bundle installed from the real tarball), any agent-bundle build with a package build plus install-capable targets failed with AB5000: Bundler stats selected a module without an authored source path.

  • Root cause: the shared install-entry runtime called new URL(options.artifactRelativeUrl, import.meta.url) with a non-literal first argument. Rspack turns that into a directory ContextModule (…/agent-bundle/dist|sync) with no nameForCondition, and the provenance collector correctly fail-closes on it. Every feat(package): package-relative host installer bins and the agent-bundle prepack inventory gate (#252) #281/test(install): empty-dir packed-tarball host-install proofs for the package-relative installer (#252) #283 gate missed this because their fixtures resolve the runtime shell from the workspace tree; the failure only reproduces when the shell is bundled out of an installed node_modules/agent-bundle/dist, which the release-lane scaffolder matrix (cli-tool journey) does.
  • Fix: the generated wrapper — which owns the baked string-literal relative URL — now resolves fileURLToPath(new URL('<literal>', import.meta.url)) itself and hands the absolute artifact root to runGeneratedInstallProcess. Statically analyzable for the bundler, identical package-relative behavior, and no weakening of the provenance collector's fail-closed posture.
  • Regression coverage rides the existing packed-consumer deleted-source journey: the consumer fixture now builds with claude/codex targets through the installed framework and asserts the emitted executable dist/bin/<name>-install.js (fails with the exact AB5000 before this fix).

Test plan

  • pnpm build, pnpm typecheck, pnpm lint — green
  • pnpm test:packed packages/agent-bundle/tests/packed-consumer.test.ts — 1 passed (failed with AB5000 pre-fix)
  • pnpm exec rstest … prepack.test.ts installer-entry.test.ts package-build.test.ts — 24 passed
  • pnpm test:packed:release …/scaffold-packed-matrix.e2e.test.ts — 2 passed (cli-tool journey's npm run build was the original failure)
  • Minimal hand repro (empty project + tarball-installed agent-bundle + claude target) builds clean and emits the installer bin

@ScriptedAlchemy
ScriptedAlchemy merged commit abf73be into main Sep 2, 2026
@changeset-bot

changeset-bot Bot commented Sep 2, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: a8a4fc5

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
agent-bundle Patch

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

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 2, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-02T06:14:13.803712Z a8a4fc5 PR opened
ℹ️ 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a8a4fc5c9d

ℹ️ 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".

'',
'process.exitCode = await runGeneratedInstallProcess(process.argv.slice(2), Object.freeze({',
` artifactRelativeUrl: ${JSON.stringify(options.artifactRelativeUrl)},`,
` artifactRoot: fileURLToPath(new URL(${JSON.stringify(options.artifactRelativeUrl)}, import.meta.url)),`,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep filesystem URL conversion inside the installer error boundary

When the project path contains a literal % (for example, /tmp/plugin%build), fileURLToPath throws URI malformed synchronously while constructing these options, before runGeneratedInstallProcess can handle --help or enter its diagnostic try block. This makes even <name>-install --help terminate with an unhandled stack trace; previously URL conversion happened after the help check and inside the try. Keep the literal new URL(...) in the generated wrapper for static analysis, but defer fileURLToPath until the runtime's guarded path (for example, by passing the URL itself or a resolver).

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 5317ce619: the generated wrapper now passes a URL, and runGeneratedInstallProcess converts it with fileURLToPath only inside the guarded execution path after help handling. Source-contract and literal-percent path regressions cover the boundary. Merged via #319.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant