* feat(review): add runtime-agnostic PR provider
Introduces `packages/shared/pr-provider.ts` with a `PRRuntime` interface
(same pattern as ReviewGitRuntime in review-core.ts) and GitHub PR
operations: URL parsing, auth check, diff/metadata fetching, and file
content retrieval via `gh` CLI.
`packages/server/pr.ts` is the Bun wrapper that pre-binds the runtime,
matching the git.ts pattern.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): add PR mode to review server
When `prMetadata` is provided to `startReviewServer`, the server enters
PR mode: `/api/diff` includes PR metadata and omits gitContext,
`/api/diff/switch` and `/api/git-add` return 400 (not applicable),
and `/api/file-content` fetches from GitHub API using base/head SHAs
instead of local git.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): PR review flow for Claude Code and OpenCode
Detects URL argument in `/plannotator-review` command. When a GitHub PR
URL is provided, fetches diff and metadata via `gh` CLI and starts the
review server in PR mode. Local review mode is unchanged when no URL
is passed.
Updates slash command definitions to pass $ARGUMENTS through.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): PR metadata display in review UI
Shows "PR Review" badge, PR title with link, and owner/repo in the
header when reviewing a pull request. Diff switcher and staging
controls auto-hide since gitContext is omitted in PR mode.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(review): contextualized PR feedback for agent
In PR mode, the feedback markdown now includes PR metadata (repo,
number, title, branches, URL) so the agent has full context about
the remote PR being reviewed. Removes the aggressive "address all
of them" instruction in PR mode since the content is self-explanatory.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor(review): extract exportReviewFeedback + add tests
Moves the pure feedback construction function from App.tsx to
utils/exportFeedback.ts so it can be unit tested. Drops the unused
`files` parameter. 11 tests covering local/PR headers, annotation
grouping, sorting, file-scope ordering, and suggested code rendering.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(review): strengthen PR/local boundary tests
Replaces shallow header checks with comprehensive boundary assertions:
local mode must never contain PR-specific content (repo, URL, branches),
PR mode must include all context fields and exclude the generic header.
Covers null/undefined prMetadata edge cases.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test(review): remove redundant empty-annotations test
Covered by the "no annotations: returns generic empty regardless of
prMetadata" test which checks all three cases (no arg, null, PR mode).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(review): guard fetchPR, fix UTF-8 decoding, correct useCallback deps
- Wrap fetchPR() in try/catch in both hook and OpenCode entry points
so network/auth errors show a clean message instead of a stack trace
- Replace atob() with Buffer.from() for UTF-8 correct base64 decoding
of PR file content from GitHub API
- Fix stale useCallback deps in handleCopyFeedback (files → prMetadata)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix(install): add $ARGUMENTS to review command for PR URL support
Install scripts were writing the review slash command without
$ARGUMENTS, so PR URLs passed to /plannotator-review were silently
dropped. Also switches PS1 heredoc to single-quoted to prevent
$ARGUMENTS from being expanded as a PowerShell variable.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add PR review support to docs and READMEs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: add /plannotator-last to READMEs and marketing docs
* feat: add /plannotator-last to install scripts
* fix: sync review command wording in install scripts with plugin
The plugin's plannotator-review.md was updated in #293 to handle
LGTM approvals but the install scripts still had the old wording.
* feat: custom theme system with 15 built-in themes
Consolidate CSS theming into a single source of truth (packages/ui/theme.css)
and introduce a multi-theme architecture where each theme defines both dark
and light mode variants. Users can pick a color palette (theme) and separately
toggle dark/light mode within it.
- Extract shared color tokens, Tailwind bridge, and base styles into packages/ui/theme.css
- Replace hardcoded oklch values with token references (oklch from var syntax)
- Fix 3 light-mode bugs in review-editor diff colors
- Create 15 built-in themes: Plannotator (default), Claude+, Soft Pop, Adwaita,
Caffeine, Cyberdyne, Cyberfunk, Doom 64, Dracula, Gruvbox, PaulMillr,
Quantum Rose, Solar Dusk, Terminal, Tinacious
- Expand ThemeProvider to manage colorTheme + mode independently
- Add Theme tab to Settings with mode toggle, search, and swatch grid
- Dark-only themes (Dracula, Terminal, etc.) suppress light class to prevent
broken styling; light-only themes (Tinacious) force it
- Cookie persistence: plannotator-color-theme for palette, existing key for mode
- Include theme conversion script for FinSitter theme adaptation
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: refine themes, add Catppuccin/Rosé Pine/Monokai Pro/Synthwave 84/Tokyo Night
Theme curation:
- Replace Cyberdyne with Synthwave '84 (from robb0wen/synthwave-vscode)
- Replace Cyberfunk with Catppuccin (Mocha dark + Latte light), Rosé Pine
(dark + Dawn light), Monokai Pro (dark only), Tokyo Night (Storm + Day)
- Rewrite Gruvbox from canonical source (morhetz/gruvbox)
- Rewrite Adwaita from canonical VS Code theme (piousdeer/vscode-adwaita)
- Rewrite PaulMillr from Ghostty canonical palette
Theme fixes:
- Fix faded Send Feedback button on Solar Dusk, Quantum Rose, Caffeine
(accent colors were too dark/invisible at 15% opacity)
- Fix Dracula/Terminal/PaulMillr/Tinacious light mode breakage — dark-only
themes now suppress .light class via modeSupport in ThemeProvider
- Fix code block backgrounds — use --code-bg token instead of --muted
- Add faint green grid overlay for Terminal theme
- Alphabetize theme registry (Plannotator first)
Code review diff theming:
- Pass theme colors into @pierre/diffs shadow DOM via unsafeCSS prop
- Dynamic themeType based on resolved mode
18 built-in themes: Plannotator, Absolutely, Adwaita, Caffeine, Catppuccin,
Doom 64, Dracula, Gruvbox, Monokai Pro, PaulMillr, Quantum Rose, Rosé Pine,
Soft Pop, Solar Dusk, Synthwave '84, Terminal, Tinacious, Tokyo Night
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: increase settings modal height for theme grid visibility
Remove 340px cap on theme grid, bump content area from 70vh to 85vh
so all themes are visible without scrolling.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: memoize ThemeProvider context, deduplicate Mode type, clean up DiffViewer
From /simplify review:
- Export Mode type from ThemeProvider, import in ThemeTab (was duplicated)
- Add resolvedMode to context — consumers no longer re-query matchMedia
- Memoize context value with useMemo, setters with useCallback (prevents
unnecessary re-renders of all useTheme consumers)
- Consolidate DiffViewer's two pierre state vars into single object
- Use resolvedMode from context in DiffViewer instead of classList check
- Format crammed single-line extended tokens in 4 theme CSS files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: prevent FOUC, fix system mode stale read, restore marketing theme class
P1: Marketing site inline script now sets theme-{name} class on <html>
before first paint (reads plannotator-color-theme cookie). Without this,
CSS tokens under .theme-* selectors were never active.
P2: System mode effect now re-reads matchMedia.matches immediately when
entering system mode, not just on future changes. Fixes stale resolvedMode
when OS preference changed while pinned to explicit dark/light.
P3: ThemeProvider applies theme class synchronously during render (not in
a passive useEffect) to prevent flash of unstyled content on hard refresh.
Also extracted resolveThemeClasses to module scope to avoid useCallback.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add Quick Copy button, fix import icon, comment out agent badge
- Add Quick Copy button to annotation panel footer (splits horizontally
with existing Quick Share). Copies annotations wrapped with the deny
preamble so output is paste-ready for agent sessions.
- Export Modal annotations copy also wraps with deny preamble
- Extract wrapFeedbackForAgent() utility in parser.ts as single source
of truth for the preamble text
- Fix desktop import icon to match mobile (arrow-into-document, not download)
- Comment out code review agent badge — unreliable across multiple harnesses
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Clear /tmp/jiti on install to avoid stale cached Pi extension. Add a
PI USERS section to the post-install output with the install command.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(annotate): support Windows markdown paths in CLI annotate flow
* fix tmp path
* fix resolve-file.ts
* Update command to use EXE_PATH variable
* Update command path for plugin hooks in install.ps1
* test: add core test suite for path resolution, storage, remote detection, and install scripts
- resolve-file: absolute paths, relative paths, case-insensitive search, ignored dirs, extension filtering, ambiguity, Windows separators
- storage: slug generation, tilde expansion, version history, deduplication
- remote: env var detection (PLANNOTATOR_REMOTE, SSH_TTY), port config and validation
- image: tmpdir usage, extension validation
- install scripts: JSON structure validation, checksum verification, arch detection, full exe path in hooks
79 tests, 35ms
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* ci: add test workflow and gate release builds on tests
- New test.yml: runs `bun test` on PRs and pushes to main
- release.yml: tests must pass before build job runs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: resolve pre-existing test failures for CI compatibility
- project.test.ts: make repo name assertion portable (works in CI where
checkout dir differs from local dev)
- vscode mock: add missing APIs needed by editor-annotations.ts
(comments, languages, Range, CodeActionKind, decorations)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: remove Viewer.test.tsx and happy-dom dependency
Tests didn't exercise any application code — they manually constructed
DOM elements inline and verified DOM API behavior, not Viewer.tsx logic.
The mock highlighter didn't simulate real hljs, and one test could never
fail due to its try/catch structure.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use targeted markdown glob and restore clean lockfile
- Replace **/* glob with **/*.[mM][dD]{,[xX]} to only scan markdown
files during case-insensitive search (avoids iterating every file)
- Restore package.json key ordering from main, only removing happy-dom
- Regenerate bun.lock from main's base to eliminate version drift
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* test: drop redundant test and fix weak assertion
- Remove redundant PLANNOTATOR_REMOTE=TRUE test (already covered by true)
- Fix UPLOAD_DIR assertion that would pass even with hardcoded /tmp
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: add Pi origin support to code review UI and update banner
Pi users were seeing "OpenCode" badge and getting the wrong update
command. Adds 'pi' to origin types in review/annotate servers, shows
violet "Pi" badge in code review header, and copies the correct
`pi install` command in the update banner.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: update Pi extension from install scripts when pi is available
The install scripts now check if `pi` is on PATH and run
`pi install npm:@plannotator/pi-extension` to update the extension.
Silent for users without Pi installed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* fix: validate plugin hooks.json on install to ensure correct timeout
The Claude Code plugin marketplace can leave stale hooks.json with
incorrect timeout values (e.g. 1800 instead of 345600). Install scripts
now check for and overwrite the plugin's hooks.json if it exists.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: warn about duplicate hook when plugin and settings.json both configure plannotator
Detects "command".*plannotator in settings.json (only matches hook configs, not
enabledPlugins) and only warns when the plugin is also installed.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: define CLAUDE_SETTINGS variable in install.cmd
The duplicate hook warning referenced !CLAUDE_SETTINGS! but the variable
was never set, causing the warning to silently never fire for CMD users.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
As per https://specifications.freedesktop.org/basedir/latest/#variables
> User-specific executable files may be stored in $HOME/.local/bin.
There is no env var for users to set to change this behaviour, and
$XDG_DATA_HOME isn't a reasonable place to put them.
Install scripts now check for the CLAUDE_CONFIG_DIR environment
variable when determining where to place the slash command file.
Falls back to the default ~/.claude/ when unset.
Closes#136
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Windows users running the bash script (via Git Bash/MSYS) may have old
binaries at different locations. Now cleans up both:
- $USERPROFILE/.local/bin/plannotator* (old bash location)
- $LOCALAPPDATA/plannotator/plannotator.exe (PowerShell location)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Helps Windows users running bash script who were stuck on old versions.
The mv command may not overwrite properly on Windows due to file locking
or .exe extension mismatch.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Users with older installations at ~/.local/bin had PATH conflicts
where the old binary took precedence over the new install location.
Now removes plannotator from old locations before installing.
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Keep clearing both ~/.cache/opencode and ~/.bun/install/cache paths
to match Windows behavior (belt and suspenders).
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The `files` array in package.json was missing plannotator.html and
review-editor.html, causing them to be omitted from npm publishes.
This explains why users were stuck on old versions.
Also fixes incorrect cache path in docs and install script.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
In Windows PowerShell 5.1, Invoke-WebRequest returns .Content as a byte
array (System.Byte[]) for non-HTML responses, not a string. This causes
the installer to fail with:
Method invocation failed because [System.Byte] does not contain a
method named 'Split'.
This fix:
- Adds -UseBasicParsing to avoid security warning prompts
- Detects if Content is byte[] and converts to string using UTF8 encoding
- Maintains compatibility with PowerShell 7+ where Content is already a string
Fixes installation on Windows PowerShell 5.1 (the default on Windows 10/11).
Co-authored-by: Tafheem Malik <maliktafheem@yvp5c.onmicrosoft.com>
- Add Windows PowerShell install script (install.ps1)
- Install slash commands for both Claude Code and OpenCode
- Update OpenCode README with install script instructions
- Simplify UpdateBanner to use same install command for both platforms
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add "after you restart Claude Code" to /plannotator-review message
- Symlink install scripts to marketing/public for automatic deploys
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
## Summary
Complete code review system for reviewing git diffs with annotations.
### Features
- Interactive diff viewer with split/unified views
- Line-level annotation system
- Diff type selector (uncommitted, last commit, vs main branch)
- Dynamic default branch detection
- Empty state handling
- Simplified UX with streamlined feedback flow
Closes#51Closes#56
OpenCode users were running the Claude Code install script and getting
confused. Added a clear banner at the end directing them to use the
npm plugin instead.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>