The workspace:* protocol is unresolvable outside the monorepo, causing
BunInstallFailedError for npm consumers. Since the build bundles
@plannotator/server into dist/index.js rather than externalizing it,
the dependency is build-time only and belongs in devDependencies.
* 🐛 fix(opencode): add missing @plannotator/server dependency
The opencode build failed because @plannotator/server was not declared
in apps/opencode-plugin/package.json, causing bun bundler to fail
resolving workspace packages.
* ✨ feat(ui): add auto-close delay with countdown on completion overlay
- Extend auto-close setting from boolean to delay options (off/immediate/3s/5s)
- Extract shared CompletionOverlay component from both editor and review apps
- Show countdown timer on completion screen when delay is set
- Add checkbox on completion overlay to enable auto-close (defaults to 3s)
- Replace toggle with select dropdown in Settings
* ♻️ refactor(ui): extract useAutoClose hook and clean up completion overlay
- Extract countdown logic into useAutoClose hook with phase state machine
- Extract SVG icons into named components (CheckIcon, ChatBubbleIcon)
- Add AUTO_CLOSE_OPTIONS constant for dropdown single source of truth
- Remove dead getAutoClose/setAutoClose boolean wrappers
* 🐛 fix(ui): handle window.close() failure with fallback message
Browsers block window.close() on tabs not opened by script. Add tryClose()
helper that detects failure via window.closed check, and show a fallback
message guiding the user to close manually.
The /api/image endpoint serves files from the local filesystem based on
a user-provided path parameter with no validation. This allows any
process on localhost to read arbitrary files (e.g., /etc/passwd,
~/.ssh/id_rsa) by requesting /api/image?path=<any-path>.
This commit adds:
- Path validation requiring image file extensions (png, jpg, gif, etc.)
- Path resolution via path.resolve() to normalize traversal sequences
- Upload extension validation against the same image allowlist
- Shared image.ts module used by all three servers (plan, review, annotate)
[agent]
* fix(browser): use open -a only for PLANNOTATOR_BROWSER on macOS
BROWSER env var follows Unix convention (executable + URL as arg),
so BROWSER=open correctly resolves to `open <url>` instead of
the broken `open -a open <url>`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix(browser): use cmd.exe only for PLANNOTATOR_BROWSER on WSL
Same fix as the macOS open -a change: when only BROWSER is set (e.g.
VS Code devcontainer helper script), execute it directly instead of
routing through cmd.exe /c start, which can't run Linux paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
* feat: use BROWSER env var as fallback for opening UI
Closes#119
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add missing reference docs (were gitignored by reference/ pattern)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Migrate marketing site from Vite React SPA to Astro 5 with documentation (15 pages) and blog. Preserves landing page design, OKLCH design system, and S3/CloudFront deploy pipeline.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: named image references and annotate command (#67, #109)
Add human-readable names to image attachments throughout the annotation
pipeline, and add a new `plannotator annotate <file.md>` command for
annotating arbitrary markdown files.
Image names: ImageAttachment type replaces plain string paths, upload
endpoints return originalName, editable name inputs under thumbnails,
[name] path format in exported feedback, backward-compatible sharing.
Annotate command: new server module reusing plan editor HTML with
mode:"annotate", CLI subcommand, slash commands for Claude Code and
OpenCode, annotate mode UI (hides Approve, shows Send Annotations).
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: move image name input to ImageAnnotator screen
The name input now appears on the full-screen annotator modal that opens
immediately when uploading/pasting an image, pre-populated from the
filename. Removes the disruptive inline name editing from thumbnails.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: stale closure in paste handler, update CLAUDE.md for new features
Fix race condition where globalAttachments was captured as empty array
in the paste event listener (missing dependency). Also update CLAUDE.md
to document ImageAttachment type, annotate server/flow, updated sharing
format with image support, and new slash commands.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add PLANNOTATOR_SHARE_URL env var so users can point share links at
their own self-hosted portal instance instead of share.plannotator.ai.
Threads the base URL through the same path as sharingEnabled: env var →
server options → API response → editor state → useSharing hook →
generateShareUrl(). Includes self-hosting guide and documentation.
Closes#12
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add drag-to-resize for the annotation panel, table of contents,
and file tree sidebar. Panel widths persist in cookie storage
across sessions and random-port hook invocations.
- Add useResizablePanel hook with left/right side support
- Extract ResizeHandle component with spread-friendly handleProps API
- Apply to AnnotationPanel, ReviewPanel, TableOfContents, FileTree
- Double-click handle to reset to default width
- Add min-w-0 on content areas for proper flex shrinking
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>
* feat: add import teammate review from share link
Adds the ability to import annotations from a teammate's plannotator
share URL into the current plan review session.
- New ImportModal component with URL input, validation, and feedback
- importFromShareUrl() in useSharing hook: decodes share link,
deserializes annotations, deduplicates, and merges into session
- Import button in header toolbar (visible when sharing is enabled)
Workflow: teammate shares their annotated plan via share link,
user clicks Import, pastes the URL, annotations are merged in.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: cleanup auto-close timer and deduplicate global attachments on import
- Clear auto-close setTimeout when user manually closes ImportModal
(prevents orphaned callback from firing after unmount)
- Deduplicate global attachment paths on import to prevent duplicates
when importing the same share link twice
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: move import button into export dropdown menu
Move "Import Review" from a standalone header button into the export
dropdown, separated by a divider. Reduces header clutter.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: razb <razb@voyager-labs.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
One-time dialog introduces Table of Contents and Sticky Actions to
new and existing users. Sequences after Permission Mode Setup dialog
if both need to show, uses cookie-based detection to avoid repeat.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Decouple Obsidian/Bear saves from the approve/deny flow so users can
save plans to their notes app independently, then manually approve in
Claude Code (e.g. shift+tab for context clearing).
- Add POST /api/save-notes server endpoint
- Add "Notes" tab to Export dialog with per-integration save buttons
- Split Export button into button+dropdown with quick actions:
Copy Share Link, Download Diff, Save to Obsidian/Bear
- Add Cmd/Ctrl+S keyboard shortcut with configurable default action
- Add "Default Save Action" setting in Settings > Saving
- New utility: defaultNotesApp.ts for cookie-based preference
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: Add Table of Contents sidebar with sticky action buttons
- Add hierarchical Table of Contents component with clickable navigation
- Implement useActiveSection hook for real-time section highlighting
- Add annotationHelpers utility for block identification
- Make Images, Global comment, and Copy plan buttons sticky during scroll
- Fix navigation scrolling to work within scrollable main container
* fix: Correct typo in opencode.json (CALUDE -> CLAUDE)
* docs: Update testing documentation - separate UI tests from integration/utility tests
* fix(ui): prevent code block annotation from breaking syntax highlighting
- Replace surroundContents() with plain text wrapper approach
- Add syntax highlighting restoration in removeHighlight()
- Fixes issue reported by kkharji in PR #122
The old approach used range.surroundContents() which wrapped syntax-highlighted
<span> elements, creating nested structure that broke the layout. The new approach
replaces code block innerHTML with plain text wrapped in <mark>, then restores
syntax highlighting when the annotation is removed.
Test coverage: 15 tests pass with edge cases for empty blocks, special chars,
large blocks (10k), unicode, and multiple annotation cycles.
* test(ui): add comprehensive code block annotation regression tests
- Add 15 test cases covering code block annotation behavior
- Test plain text wrapper approach vs nested span approach
- Verify syntax highlighting restoration on annotation removal
- Cover edge cases: empty blocks, special chars, large blocks, unicode
- Add happy-dom dev dependency for DOM testing
* feat: update opencode.json to include additional documentation instructions and configure Playwright MCP
* chore: stop tracking docs directory and opencode.json
* chore: move UI-TESTING.md to tests directory
* docs: extract UI testing checklist into separate file
- Move comprehensive feature checklists to UI-TESTING-CHECKLIST.md
- Keep main UI-TESTING.md focused on development workflow and setup
- Add reference link to checklist file for easy navigation
* docs: update UI testing documentation
* fix(ui): fix TOC active section tracking
IntersectionObserver was using root: null (viewport) instead of the
actual scroll container (<main>), and the effect only ran on mount
before headings were rendered. Pass the container as root and re-run
the observer when heading count changes.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* revert: remove Playwright MCP from marketplace.json and stale README links
Playwright MCP is dev tooling, not for end users. README referenced
docs/UI-TESTING.md and docs/CODE-STYLE.md which don't exist at those paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* style(ui): compact TOC styling and fix layout shifts
- Smaller text (text-xs) and tighter padding for compact feel
- Remove border-l-2 and font-medium from active state to prevent
layout shifts that pushed text into multiline
- Annotation count badges are now perfect circles (w-5 h-5)
- Add left padding to root-level heading
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat(ui): add optional TOC and sticky actions settings
- New uiPreferences.ts utility for cookie-based persistence
- TOC toggle: conditionally renders sidebar in App.tsx
- Sticky Actions toggle: conditionally applies sticky positioning in Viewer.tsx
- Both default to enabled, persisted via cookies
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor(ui): redesign Settings dialog with sidebar navigation
Replace flat settings list with sidebar + content panel layout:
- General tab: Identity, Permission Mode, Agent Switching
- Display tab: TOC, Sticky Actions, Tater Mode
- Saving tab: Plan Saving, Obsidian, Bear Notes
- Scrollable content area (max-h-[70vh])
- Sidebar hidden in review mode (single tab)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(ui): fix sticky action bar positioning and add scroll-aware card background
Match main's button positioning across all breakpoints with responsive
margins that account for article padding. Use IntersectionObserver sentinel
to detect when the bar is stuck, revealing the card background only on scroll.
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: display repo and branch info in plan document
Add subtle badge display in upper-left corner of plan document showing:
- Repository name (org/repo from git remote, with fallbacks)
- Current branch with git branch icon
New modular repo.ts handles detection with fallback chain:
1. Parse org/repo from git remote origin
2. Fall back to git repo root directory name
3. Fall back to current working directory
Closes#104
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* test: add --no-git flag to sandbox script
Allows testing repo info fallback behavior when not in a git repository.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
- Detect mermaid code blocks and render as interactive diagrams
- Dark theme matching Plannotator UI
- Toggle between source code and rendered diagram view
- Use getBBox() to recalculate viewBox for proper centering
- Error state shows source code fallback
- Add mermaid diagram to demo plan
Closes#115
Co-authored-by: Claude Opus 4.5 <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>
Add agent filtering to experimental.chat.system.transform hook to prevent
injecting plan submission prompts into agents that shouldn't receive them:
- Hardcoded exclusion for "build" agent
- Dynamic exclusion for agents with mode "subagent" (e.g., general, explore)
- Skip injection if agent detection fails (safer behavior)
The plan agent and other primary agents will continue to receive the prompt.
Co-authored-by: cognitive <152830360+METAeuPHORIC@users.noreply.github.com>
- Add new "Comment" editor mode that shows input directly on selection
- Add type-to-comment in Selection mode: typing while toolbar is open
auto-transitions to comment input with the typed character
- Add initialStep/initialType props to AnnotationToolbar for direct input
- Fix autofocus timing for portal-rendered toolbar
Closes#93
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Addresses community feedback on v0.6.6 sub-agent fix:
1. Add `config` hook to register `submit_plan` in `primary_tools`
- OpenCode natively hides these tools from ALL sub-agents
- Works for custom sub-agents too, not just general/explore
2. Replace buggy `chat.message` hook with `experimental.chat.system.transform`
- chat.message was persisting the reminder to ALL user messages
- system.transform injects once into system prompt
3. Remove hardcoded runtime sub-agent check
- No longer needed with primary_tools handling it
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Increases the plannotator hook timeout from 30 minutes to 4 days
(345600 seconds) to prevent the server from being killed during
extended plan review sessions.
Fixes#84
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
* fix: use @plannotator/web-highlighter for proper newline handling
- Switch from web-highlighter to @plannotator/web-highlighter@0.8.1
- Use source.text from highlighter (preserves newlines in cross-block selections)
- Update dependency to ^0.8.1 which fixes exports field for bundlers
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* feat: add Cmd+C keyboard shortcut for copying selected text
Closes#60
When text is selected and the annotation toolbar is visible, Cmd+C (Mac)
or Ctrl+C (Windows/Linux) will copy the selected text with proper newlines
preserved between block elements.
This works because @plannotator/web-highlighter@0.8.1 now captures text
using Selection.toString() which preserves newlines for cross-block
selections.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* fix: don't intercept Cmd+C in input/textarea fields
Prevents the custom copy handler from intercepting Cmd+C when the user
is focused in an input or textarea (e.g., annotation comment input).
Previously, copying text from an input would copy the original plan
selection instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>