feat(extension): MV3 shell, content script, and side panel — completes Phase 0#5
Conversation
Completes Phase 0 with apps/extension — the browser extension that turns the thread on the current page into a clean, readable side-panel view, wiring the live DOM through @forumforge/parser and the @forumforge/core post model. - background.ts: thin MV3 service worker; toolbar action opens the side panel. - content.ts: extracts the thread; injected on demand via activeTab + scripting (no host permissions, no standing page access), idempotent re-injection. - sidepanel.ts + sidepanel.html: 'Read this thread' injects the content script, requests extraction, and renders the result. - render.ts: read-only view written with textContent only — untrusted page content (incl. contentHtml) can never inject markup. Rich sanitized rendering is Phase 1. - extract.ts: the seam where a site-specific adapter is chosen later (Phase 2), generic parser as fallback. - messaging.ts: typed protocol validated with guards across the page boundary. - esbuild build (build.mjs) bundles to dist/; minimal webext.d.ts instead of a heavy @types/chrome dep. Tooling: esbuild dev dependency; root 'build' script and CI build step; vitest includes apps/**/test. Docs synced (README, ROADMAP, Initial Plan checklist, app README, .memory lesson). Verification: pnpm -r typecheck passes; pnpm test — 55 tests pass (8 new); pnpm build bundles the extension; pnpm install --frozen-lockfile passes.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 128268ebe5
ℹ️ 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".
…icked
setPanelBehavior({ openPanelOnActionClick: true }) opens the side panel but
does not confer the activeTab grant the panel needs to read the page
(crbug.com/40916430). With no host permissions, the panel's executeScript then
rejected on ordinary forum pages, sending "Read this thread" into the error
handler. Handle the toolbar click via chrome.action.onClicked and open the
panel programmatically so the click's activeTab grant covers the tab and
on-demand content-script injection succeeds.
Update the minimal webext typings: add chrome.action.onClicked and
sidePanel.open, drop the now-unused setPanelBehavior.
https://claude.ai/code/session_01WRRAzKehcHPUhGNibdiGp7
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 522fec7c88
ℹ️ 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".
| // as a classic script, so keep every entry consistent. | ||
| format: "iife", | ||
| platform: "browser", | ||
| target: ["chrome114"], |
There was a problem hiding this comment.
Raise the Chrome compatibility floor to 116
On Chrome 114 or 115, which this build explicitly targets and the manifest does not exclude, clicking the toolbar action calls chrome.sidePanel.open() and fails before the panel can open because Chrome's API documentation states that open() was introduced in Chrome 116. Target Chrome 116 and add the corresponding minimum_chrome_version, or use an API available in Chrome 114.
Useful? React with 👍 / 👎.
Summary
Completes Phase 0 — Foundation by landing
apps/extension, the browserextension that ties the foundation packages together end-to-end: the thread on
the current page →
@forumforge/parser→ the@forumforge/corepost model → a clean, read-only sidepanel view. With the three earlier packages (#3, #4) merged, this lands the
remaining Phase 0 roadmap items — extension shell, content script, side panel
UI — as real, unit-tested, buildable code (no placeholder stubs, per
AGENTS.md).What's included
src/background.ts— thin MV3 service worker (the shell); the toolbaraction opens the side panel.
src/content.ts— extracts the thread from its page and replies. Injectedon demand into the active tab, with idempotent re-injection.
src/sidepanel.ts+public/sidepanel.html— the panel UI: a buttonthat injects the content script, requests extraction, and renders the result.
src/extract.ts— the seam where a site-specific adapter will be chosenlater (Phase 2); today it always uses the generic parser.
src/render.ts— builds the view withtextContentonly, neverinnerHTML.src/messaging.ts— typed request/response protocol, validated with typeguards because messages cross the untrusted page boundary.
build.mjs(esbuild) bundles entries todist/and copies themanifest + panel HTML. Minimal
webext.d.tsinstead of a heavy@types/chrome.Privacy & security
activeTab+scripting+sidePanelonly — no hostpermissions, no declared content script, no standing access to pages the user
hasn't invoked ForumForge on. The content script runs only on the tab the user
clicks on (
activeTabgranted on that gesture). See docs/PRIVACY.md.as text via
textContentand never injects markup, so a maliciouscontentHtmlor author string can't run (see SECURITY.md). A unit test asserts
this. Rich, sanitized
contentHtmlrendering is Phase 1 clean reading mode.Design notes
packages/*are source-only with nobuild step, but a browser can't resolve workspace TS imports, so the extension
has a genuine esbuild bundle. All entries are classic IIFE scripts because a
content script injected via
scripting.executeScript({ files })runs as aclassic script.
bundling need).
Roadmap (Phase 0 — now complete)
packages/corepackages/parserpackages/storageapps/extension(background service worker + MV3 manifest)apps/extension(content.ts, on-demand injection)apps/extension(sidepanel.ts+renderThread)Docs synced in the same change:
README.md,ROADMAP.md, the canonicalInitial Plan.mdchecklist, a packageREADME.md, and a.memory/lesson. CInow also builds the extension (
pnpm build).Verification
pnpm -r typecheck— passes (core + parser + storage + extension)pnpm test— 55 tests pass (8 files; 8 new: messaging guards, extractionwiring, rendering incl. the XSS-safety guarantee)
pnpm build— bundlesapps/extensiontodist/pnpm install --frozen-lockfile— passes (lockfile updated for esbuild)Intentionally not done
browser); the unit tests and the bundle build are automated, and the manual
load/click-through steps are documented in the app README. No browser-in-CI
added — that's a heavier follow-up.
contentHtmlrendering with sanitization is deliberately Phase 1(clean reading mode), not Phase 0.
https://claude.ai/code/session_01PDzDar5vUbJ5Ez1Kc1JYiy
Generated by Claude Code