Skip to content

feat(extension): migrate from webpack/rspack to WXT build framework#131

Merged
lcomplete merged 8 commits into
mainfrom
dev
Apr 16, 2026
Merged

feat(extension): migrate from webpack/rspack to WXT build framework#131
lcomplete merged 8 commits into
mainfrom
dev

Conversation

@lcomplete
Copy link
Copy Markdown
Owner

Summary

  • Migrated browser extension build system from webpack/rspack to WXT framework
  • Introduced modern entrypoints directory structure (popup, options, background, content scripts, sidepanel)
  • Added sidepanel feature with React components and routing for enhanced UX
  • Created ai-elements UI component library for consistent styling across AI features
  • Added qwen compatibility test for AI providers
  • Updated build scripts: yarn dev, yarn build, yarn zip for WXT workflow

Key Changes

  • Build system: Replaced webpack/rspack configs with wxt.config.ts supporting Chrome and Firefox
  • Structure: New entrypoints/ directory following WXT conventions
  • Features: Added sidepanel with agent commands, model bridge, session storage
  • Components: New ai-elements/ components (conversation, message, reasoning, sources, suggestion, tool)
  • Tests: Added qwenCompatibility.test.ts for AI provider testing
  • Cleanup: Removed deprecated webpack configs and public manifest files

Test plan

  • Run yarn dev to verify WXT dev server starts correctly
  • Run yarn build to verify production build succeeds
  • Run yarn test to verify all tests pass
  • Run yarn typecheck to verify TypeScript compilation
  • Load extension in Chrome and Firefox to verify functionality
  • Test popup, options, sidepanel, and content scripts work as expected

🤖 Generated with Claude Code

lcomplete and others added 6 commits April 12, 2026 19:06
…ponse handling; add unit tests for McpServerController
- Replace webpack/rspack with WXT for modern browser extension development
- Add WXT config with Chrome and Firefox target support
- Introduce entrypoints directory structure (popup, options, background, content scripts)
- Add sidepanel feature with React components and routing
- Create ai-elements UI component library for consistent styling
- Update build scripts: dev, build, zip for WXT workflow
- Add qwen compatibility test for AI providers
- Update all source files to adapt to WXT module system and APIs
- Remove deprecated webpack configs and public manifest files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Apr 16, 2026

This pull request is abnormally large and would use a significant amount of tokens to review. If you still wish to review it, comment augment review and we will review it.

@lcomplete
Copy link
Copy Markdown
Owner Author

augment review

@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Apr 16, 2026

🤖 Augment PR Summary

Summary: This PR migrates the browser extension build system from webpack/rspack to the WXT framework, restructures entrypoints, and adds significant new features.

Changes:

  • Replaced webpack/rspack configs with wxt.config.ts supporting Chrome and Firefox builds
  • Introduced WXT-style entrypoints/ directory for popup, options, background, content scripts, and sidepanel
  • Added a new AI chat sidepanel feature with React components, tool-loop agent, session storage (IndexedDB), model selection, and slash commands
  • Created ai-elements/ UI component library (conversation, message, reasoning, sources, suggestion, tool) adapted from Vercel's ai-elements
  • Added Qwen compatibility layer for reasoning/thinking mode with tests
  • Updated providers.ts to use provider.chat(model) instead of provider(model)
  • Added context menu items for opening the sidepanel chat
  • Added a Sponsor settings page with QR code payment methods
  • Fixed MCP server controller to return empty 202 responses for content negotiation compatibility
  • Refactored background.ts and content scripts to use init*() wrapper functions for WXT compatibility

Technical Notes: The sidepanel uses AI SDK's ToolLoopAgent for multi-step tool execution. The sidePanel permission and scripting permission are missing from the WXT manifest config, which will prevent the sidepanel and dev-mode content script registration from working correctly.

🤖 Was this summary useful? React with 👍 or 👎

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 5 suggestions posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.

action: {
default_icon: icons,
},
permissions: ["storage", "tabs", "contextMenus"],
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 16, 2026

Choose a reason for hiding this comment

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

The sidePanel permission is missing from the manifest permissions array. The sidepanel entrypoint exists at entrypoints/sidepanel/, and the background script calls chrome.sidePanel.open(), but without the "sidePanel" permission the API will be unavailable and the sidepanel won't register. Similarly, the "scripting" permission is needed for chrome.scripting.registerContentScripts() in entrypoints/background.ts.

Severity: high

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

{}
);

Promise.resolve(run(stores))
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 16, 2026

Choose a reason for hiding this comment

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

Race condition: the transaction.oncomplete/onerror handlers are set after the run(stores) promise resolves, but IndexedDB transactions auto-commit when all their requests finish and the microtask queue is empty. If run() only fires synchronous IDB requests (which requestToPromise wraps), the transaction may already have completed or errored by the time these handlers are attached, causing the outer promise to never resolve.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

Comment thread app/extension/src/content_script.tsx Outdated
// Setup RSS feed detection listener
setupRssDetectionListener();
window.addEventListener("message", function (event: MessageEvent<Message>) {
if (event.data && typeof event.data.type === 'string' && !event.data.type.includes('wxt:')) {
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 16, 2026

Choose a reason for hiding this comment

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

The filter !event.data.type.includes('wxt:') uses includes which is a substring match — any message type containing wxt: anywhere in the string will be silently dropped. Consider using startsWith('wxt:') for a more precise check, since WXT internal messages use the wxt: prefix.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

status: "complete",
};

const allMessages = [...messages, userMsg];
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 16, 2026

Choose a reason for hiding this comment

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

The sendMessage callback captures messages from state in its closure (dependency array line 581). If runAgent triggers state updates that change messages before the next render, a rapid second sendMessage call could use a stale messages snapshot, potentially losing the first message. Consider using a ref or functional state updater to always read the latest messages.

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

info: chrome.contextMenus.OnClickData,
tab?: chrome.tabs.Tab
): Promise<void> {
const targetTab = await resolveContextMenuTab(tab);
Copy link
Copy Markdown

@augmentcode augmentcode Bot Apr 16, 2026

Choose a reason for hiding this comment

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

chrome.tabs.sendMessage to targetTab.id will fail here because targetTab.id is typed as number | undefined — the targetTab?.id guard on line 953 only checked that targetTab had an id, but the inner callback references targetTab.id without the ! assertion while TypeScript would flag it. More importantly, if the content script hasn't loaded, this sendMessage will silently fail with no user feedback.

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

@lcomplete lcomplete merged commit d79c64a into main Apr 16, 2026
1 check passed
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