Commit Graph

343 Commits

Author SHA1 Message Date
Michael Ramos 54e951e2f7 fix: don't ask agent to address feedback on LGTM approval (#293)
* fix: don't ask agent to address feedback on LGTM approval (#284)

When the reviewer approves with no annotations, send a neutral
"Code review completed — no changes requested." message instead of
the contradictory "LGTM" + "Please address this feedback."

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: use explicit approved flag instead of annotations.length heuristic

The previous fix inferred LGTM from an empty annotations array, but
VS Code editor annotations are carried in feedbackMarkdown without
populating the annotations array — causing real review comments to be
misclassified as approvals. Thread an explicit `approved` boolean from
the UI through the review server to all three integrations.

Closes #284

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: append assertive instruction to review feedback output

When the reviewer submits actual feedback, append "The reviewer has
identified issues above. You must address all of them." so the agent
treats annotations with urgency rather than soft-acknowledging them.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: annotate unused LGTM feedback string

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-14 17:58:57 -07:00
Marcelo Terreiro Prado d7ccc55f33 feat: configurable Bear tags + fix double-title bug (#283)
* feat: configurable Bear tags + fix double-title bug

- Fix double title: strip H1 from Bear note body since `title` URL
  param already carries it
- Add custom tags setting (comma-separated, kebab-case) with
  auto-normalization; empty = auto-generated tags (existing behavior)
- Add tag position setting: prepend (after title) or append (default)
- Settings UI in Bear tab with inputs matching existing design
- Dev mock: add /api/approve + /api/save-notes handlers for Bear
  testing in dev mode

* revert: drop dev-mock-api changes

* fix: simplify H1 stripping regex — no wording assumption

* test: add Bear integration tests + restore JSDoc comments

* refactor: export Bear helpers from integrations, import in tests

* test: use dummy title in Bear tests
2026-03-12 16:30:51 -07:00
Michael Ramos 74ccf42fbe chore: bump version to 0.12.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 01:09:21 -07:00
dgrissen2 59724b7fe2 fix: enable linked doc navigation in annotate mode (#276)
The annotate server was missing the /api/doc endpoint, so clicking
.md links (e.g., [see other](sibling.md)) in annotated files showed
"Failed to connect to server" — the request fell through to the SPA
catch-all and returned HTML instead of JSON.

Three changes:

1. annotate.ts — Add /api/doc route, auto-injecting the source
   file's parent directory as ?base= so relative links resolve
   from the correct location.

2. reference-handlers.ts — handleDoc() now accepts an optional
   ?base= query param and tries resolving relative paths against
   it before falling back to the project-root glob search.

3. App.tsx — handleOpenLinkedDoc passes the current file's
   directory as ?base= when navigating linked-doc → linked-doc,
   so chained relative links resolve correctly.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 23:10:54 -07:00
dgrissen2 2d1016a3fd feat: render markdown images with lightbox zoom (#271)
Adds full inline image rendering to the Viewer for both annotate and
plan review modes. Previously, ![alt](path) syntax was treated as plain
text.

## What changed

### Viewer.tsx
- Added `![alt](path)` regex to InlineMarkdown before the link pattern.
  Images starting with `!` were silently falling through to plain text
  because `!` was not in the special-character scan set — added it.
- Added `imageBaseDir` prop (flows Viewer → BlockRenderer → InlineMarkdown)
  so relative image paths in markdown resolve against the annotated file's
  directory rather than the server's cwd.
- Added `onImageClick` callback (same prop chain) to open lightbox on click.
- Added `ImageLightbox` component: full-screen dark backdrop, image scaled
  to 90vw/85vh with object-contain, alt text caption, closes on Escape or
  backdrop click. Portaled to document.body.
- Images render with `cursor-zoom-in` to hint they're clickable.

### App.tsx
- Captures `filePath` from `/api/plan` response (already sent by annotate
  server) and derives `imageBaseDir` (directory of the markdown file).
- Passes `imageBaseDir` to `<Viewer>`.

### ImageThumbnail.tsx
- `getImageSrc()` now accepts an optional `base` parameter. For relative
  local paths, appends `&base=<dir>` to the `/api/image` query string.

### shared-handlers.ts
- `handleImage` falls back to resolving the path relative to a `base`
  query param when the primary path doesn't exist and the path is relative.
  Covers the common case of `![chart](./images/chart.png)` in a markdown
  file opened from an arbitrary directory.

## Behavior
- Remote URLs (https://...) render directly, no proxy.
- Absolute local paths route through /api/image as before.
- Relative paths resolve against the markdown file's directory via ?base=.
- Click any image → lightbox. Escape or click outside → dismiss.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-03-11 18:48:05 -07:00
Barbaros G. f650ef9cb0 fix: open browser in SSH remote when PLANNOTATOR_BROWSER is set (#259) (#274)
When VS Code extension sets PLANNOTATOR_BROWSER, always call openBrowser()
even in remote sessions, so the extension's open-in-vscode handler is used.
2026-03-11 07:37:25 -07:00
김영준E 41059d8e43 fix: Support Windows markdown paths in CLI annotate flow (#267)
* 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>
2026-03-10 17:47:07 -07:00
Michael Ramos b6bec6943b feat: add Pi origin support to code review UI (#263)
* 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>
2026-03-09 23:41:29 -07:00
Michael Ramos bd8268de6c chore: bump version to 0.11.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:40:50 -07:00
Michael Ramos d29dd08c13 feat: git add files from code review UI (#257)
* feat: add per-file git add from code review UI (#254)

Adds the ability to `git add` individual files directly from the code
review interface. Users can stage approved files then switch to the new
"Unstaged changes" diff view to see only remaining work.

- POST /api/git-add endpoint with worktree support
- gitAddFile/gitResetFile utilities in packages/server/git.ts
- "Staged changes" and "Unstaged changes" added to diff type dropdown
- useGitAdd hook encapsulating all staging state and API logic
- "Git Add" / "Added" toggle button in FileHeader (next to Viewed)
- Visual indicator (left border) for staged files in sidebar FileTree

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* style: use green background tint for staged files instead of left border

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: support staged/unstaged diffs in worktrees and display stage errors

Adds "staged" and "unstaged" to worktree sub-type allowlists (server parser,
client parser, and runGitDiff switch), displays stageError in FileHeader,
and documents /api/git-add in CLAUDE.md.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: clean up git add feature — fix stale closure, timeout leak, dedup validation

- useGitAdd: use ref for stagedFiles to stabilize stageFile callback,
  clear error timeout on reset, drop unnecessary useMemo
- App.tsx: wrap onFileViewed in useCallback
- FileTree: merge duplicate staged count conditionals
- review.ts: reuse exported validateFilePath for /api/file-content

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 07:31:17 -07:00
dgrissen2 190f7ec412 feat: clipboard paste for per-annotation images & fix absolute path resolution (#255)
Add capture-phase paste listener to AttachmentsButton so users can
Cmd+V / Ctrl+V images directly into per-annotation attachments when
the popover is open. Uses stopPropagation to prevent the global paste
handler in App.tsx from also processing the event. Adds a platform-aware
keyboard shortcut hint in the drop zone.

Also fixes a regression from #237 where resolveMarkdownFile rejected
absolute paths outside the project root. The original behavior allowed
any absolute path the user explicitly provided; the security boundary
should only apply to relative path / bare filename search.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-09 06:35:03 -07:00
Michael Ramos c7532863c6 chore: bump version to 0.11.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:31:51 -07:00
Michael Ramos 933f44737e feat: split worktree/diff-type into separate controls (#248)
* feat: split worktree/diff-type into separate controls

The single dropdown that mixed diff type selection (uncommitted, last-commit,
branch) with worktree switching was confusing — entering a worktree silently
replaced all dropdown options with no persistent indicator of which worktree
was active.

Split into two controls:
- Context dropdown: switches between main repo and worktrees (only shown
  when worktrees exist, highlighted when a worktree is active)
- View dropdown: always shows the same diff type options regardless of context

Server changes:
- GitContext now exposes worktrees as a separate field
- Removed getWorktreeDiffOptions() and back-to-main sentinel handling
- Simplified /api/diff/switch (no more diffOptions replacement)

Client changes:
- New activeWorktreePath state + handleWorktreeSwitch callback
- handleDiffSwitch composes worktree prefix from context automatically
- Derived activeDiffBase strips worktree prefix for dropdown display

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: derive activeWorktreePath from diffType instead of separate state

Eliminates redundant state — activeWorktreePath and activeDiffBase are
now both derived in a single useMemo from the composite diffType string.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: move DiffOption, WorktreeInfo, GitContext to @plannotator/shared

Eliminates duplicate interface definitions across server and client.
Types now live in packages/shared/types.ts and are imported by both
packages/server/git.ts and packages/review-editor/.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 16:15:14 -07:00
Michael Ramos 472e17be3d feat: expandable diff context in code review (#247)
* feat: expandable diff context in code review (closes #243)

Switch from PatchDiff to FileDiff component from @pierre/diffs to enable
GitHub-style "show more lines" buttons between hunks. The library handles
all expansion UI when provided full file contents via oldLines/newLines.

- Add /api/file-content endpoint to serve old/new file content per diff type
- Add getFileContentsForDiff() helper with ref mapping for all diff types
- Parse patch client-side via getSingularPatch(), augment with file contents
- Update @pierre/diffs from 1.0.4 to 1.0.11 (scroll sync fix, no breaking changes)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: upgrade @pierre/diffs to beta, re-parse patch with full file contents

The previous approach spread file content arrays onto a partial-mode
FileDiffMetadata, causing hunk index mismatches and Shiki decoration
errors. Now uses processFile() to re-parse the patch with oldFile/newFile
so hunk indices are computed against the full file (isPartial: false),
which is required for expansion to work correctly.

Also fixes a flash error on file switch by tagging fileContents with the
filePath they were fetched for, preventing stale contents from being
paired with the wrong patch during the render before useEffect fires.

- Upgrade @pierre/diffs from ^1.0.x to ^1.1.0-beta.19 in all workspaces
- Add test fixtures for disjoint hunks, deleted/renamed/new files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: abort stale file-content fetches, validate path params

- Add AbortController to file-content fetch effect to cancel in-flight
  requests when switching files
- Reject path traversal (.. or absolute paths) on /api/file-content
- Document /api/file-content endpoint in CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-08 14:00:43 -07:00
Michael Ramos a6361356b9 chore: bump version to 0.11.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:38:06 -08:00
Michael Ramos cb4de46636 feat: VS Code editor annotations + theme integration (#239)
* feat: add shared EditorAnnotation type

Single source of truth for the editor annotation interface,
imported by both @plannotator/server and @plannotator/ui.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: editor annotation server endpoints

In-memory store with POST/GET/DELETE endpoints for editor annotations.
The array lives in the handler closure and dies with the server session.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: editor annotation UI — polling hook, card, panel, and export

- useEditorAnnotations hook with auto-disable polling (500ms interval)
- EditorAnnotationCard with file path, code preview, and comment
- AnnotationPanel conditionally renders editor annotation section
- exportEditorAnnotations formats annotations for Claude feedback
- App.tsx wires hook, includes in output memo and send feedback gate

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: VS Code extension editor annotation command

Cmd+Shift+. or right-click to capture selected text as an annotation.
POSTs through the cookie proxy to the plannotator server. Adds amber
left-border decorations on annotated lines, cleared on panel close.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: inline comment threads, lightbulb menu, and stronger decorations

Replace showInputBox with VS Code CommentController for inline annotation
threads anchored to selected code. Add CodeActionProvider for lightbulb
discoverability. Stronger decoration styling with gutter icon.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: VS Code theme integration for webview

Bridge VS Code CSS variables to Plannotator's CSS variable system via
postMessage between wrapper page and proxied iframe. Automatically adopts
the active VS Code color theme (dark/light/custom) without touching any
UI components or CSS files.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: gate editor annotation polling behind VS Code detection

Only poll /api/editor-annotations when running inside a VS Code webview
(window.__PLANNOTATOR_VSCODE). Browser and shared URL users now have
zero network cost from the editor annotations feature. Also fixes poll
interval from 500ms to 2000ms.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: faster polling, prevent unnecessary re-renders, unify HTTP helper

- Poll interval 2s → 500ms for snappier annotation pickup
- Shallow equality check on annotation IDs prevents React re-renders
  when poll data is unchanged
- Merge postToProxy/deleteFromProxy into single requestProxy function

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: editor annotations support in code review

Wire existing editor annotation infrastructure into the review flow
so VS Code users can annotate files outside the diff during code review.

- Add editor annotation endpoints to review server (same 3-line pattern)
- Call useEditorAnnotations hook in review App.tsx
- Display editor annotations in ReviewPanel with "Editor" divider
- Include editor annotations in feedback export and gating logic

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 12:25:02 -08:00
Michael Ramos 411e1b932d feat: support git worktrees in code review (#241)
feat: support git worktrees in code review (#196)

Adds full worktree support to the code review flow:

- Detects worktrees via `git worktree list --porcelain` and surfaces them in the diff dropdown
- Selecting a worktree enters "worktree mode" with scoped diff options (uncommitted, last commit, vs main)
- "Back to main repo" restores the original dropdown
- Handles initial commits gracefully (no HEAD~1 crash)

Closes #196
2026-03-07 10:06:55 -08:00
Michael Ramos c2037b78bf feat: --browser CLI flag & session discovery (#242)
* feat: add --browser CLI flag and session discovery (#135)

- Add `--browser <name>` global flag to override which browser opens
  (sets PLANNOTATOR_BROWSER, works with existing openBrowser() logic)
- Add `plannotator sessions` subcommand to list active server sessions
  with `--open [N]` to reopen in browser and `--clean` to prune stale entries
- Track active sessions in ~/.plannotator/sessions/<pid>.json with
  automatic stale cleanup via PID liveness checks
- Register/unregister sessions in all three server modes (plan, review, annotate)
- Export ./sessions and ./project from @plannotator/server package

Closes #135

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add integration test for session discovery

Non-interactive test script that validates:
- Session file creation/cleanup lifecycle
- Session file content (all fields)
- `plannotator sessions` listing, --open, --clean
- Stale PID auto-cleanup

Also syncs bun.lock versions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add --browser flag and session discovery to configuration page

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add troubleshooting page

Covers lost tabs (sessions --open), data storage locations,
browser issues, and hook not firing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 09:45:33 -08:00
Michael Ramos 75968541c2 feat: Obsidian saving enhancements — separator, auto-save, sanitization (#240)
* fix: harden title sanitization for Obsidian filenames

Strip parentheses, brackets, curly braces, hash, tilde, and backtick
from plan titles when generating Obsidian filenames. Re-trim after
stripping to handle edge cases where stripped chars leave leading/trailing
whitespace. Closes part of #235.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: filename separator + auto-save on arrival for Obsidian

Filename separator: adds a dropdown in Obsidian settings to replace
spaces with dashes or underscores in generated filenames. Fixes issues
with CLI tools fumbling space-escaped paths inside Obsidian vaults.
The setting flows through the save request to generateFilename() as a
post-processing step. Live preview reflects the choice.

Auto-save on arrival: adds an opt-in toggle that automatically saves
plans to Obsidian the moment they load in the browser, before the user
approves or denies. This fixes the workflow where approving from the
Claude Code CLI kills the hook server before the user can Cmd+S.
Guarded by a ref to fire only once per session.

Closes #235, closes #228.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: pass filenameSeparator in ExportModal Obsidian save path

The ExportModal's save-to-Obsidian callsite was missing the
filenameSeparator config, causing the separator preference to be
silently ignored when saving via the Export Modal.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 09:27:11 -08:00
dgrissen2 026194ad06 feat: smart file resolution for plannotator annotate (#237)
Add case-insensitive file resolution so users can open markdown files
without typing exact paths. Applies to both the CLI (`plannotator
annotate`) and the `/api/doc` endpoint for linked documents.

Resolution strategies (tried in order):
1. Exact path — absolute or relative to cwd (existing behavior)
2. Case-insensitive relative path — `docs/setup.md` matches `docs/SETUP.md`
3. Bare filename search — `setup.md` searches the entire project tree

Ambiguity handling:
- 1 match → opens the file, prints "Resolved: /full/path"
- 0 matches → "File not found: <input>"
- 2+ matches → "Ambiguous filename: found N matches" with full paths

Skips node_modules, .git, dist, build, .next, __pycache__, .obsidian,
.trash during search. Restricts results to .md/.mdx/.markdown files
and enforces project root boundary (no path traversal).

Extracted shared resolveMarkdownFile() into packages/server/resolve-file.ts
and refactored /api/doc handler to use it, removing ~40 lines of inline
resolution logic.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-03-07 08:09:57 -08:00
Michael Ramos 0ce299dd92 chore: bump version to 0.11.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 01:09:31 -08:00
Michael Ramos 1701424b4e feat: VS Code extension for in-editor plan review (#229)
* feat: integrate VS Code extension from community (7tg/plannotator-vscode)

Opens Plannotator plan reviews, code reviews, and annotations inside VS Code
tabs instead of an external browser. Intercepts PLANNOTATOR_BROWSER via env
var injection in integrated terminals, with cookie persistence and auto-close.

Original repository: https://github.com/7tg/plannotator-vscode
Closes #91

Co-Authored-By: Barbaros Gören <tayyipgoren@gmail.com>

* chore: adapt VS Code extension for monorepo

- Update package.json: publisher → backnotprop, repo → plannotator, add private
- Replace node -e URL encoding with curl --data-urlencode in router script
- Simplify panel-manager tests to keep only behavioral tests
- Add dev:vscode, build:vscode, package:vscode scripts to root
- Add *.vsix to .gitignore
- Update bun.lock with new workspace member

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review and duplicate panel issue

- Fix macOS browser: detect script paths in PLANNOTATOR_BROWSER and
  invoke directly instead of via 'open -a' (which only accepts app
  names/.app bundles)
- Update CLAUDE.md: add vscode-extension to project structure,
  development, and build sections
- Fix command title: 'Simple Browser' -> 'Open URL in Editor'
- Add 1s debounce to panel opens: Claude Code fires ExitPlanMode hook
  twice, spawning two plannotator processes on different ports that
  both hit the IPC server simultaneously
- Add .vscode/launch.json + tasks.json for F5 debugging

---------

Co-authored-by: Barbaros Gören <tayyipgoren@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-05 16:56:57 -08:00
zerone0x b7bc82c607 fix: include untracked new files in uncommitted/unstaged diffs (#227) 2026-03-05 03:19:01 -08:00
Michael Ramos 7110f14f56 chore: bump version to 0.11.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 16:55:38 -08:00
Michael Ramos aa71ede0f3 Auto-save annotation drafts to survive server crashes (#217)
* feat: auto-save annotation drafts to survive server crashes

Adds server-side draft persistence so annotations are not lost when the
server process dies. Drafts are saved to ~/.plannotator/drafts/ keyed by
a SHA-256 content hash, debounced at 500ms. On reload, a dialog prompts
the user to restore or dismiss. Drafts are auto-deleted on approve/deny/feedback.

Closes #212

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: remove duplicate imports and update CLAUDE.md for draft feature

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: wrap handleRestoreDraft in useCallback and update shared-handlers comment

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-04 10:12:58 -08:00
Michael Ramos d9c2d46113 refactor: extract shared route handlers and modularize plan server (#214)
* refactor: extract shared route handlers and modularize plan server

Pull duplicated /api/image, /api/upload, /api/agents handlers and
handleServerReady into shared-handlers.ts. Move /api/doc and Obsidian
reference endpoints into reference-handlers.ts. Eliminates ~120 lines
of verbatim duplication across index.ts, review.ts, and annotate.ts.

Closes #210

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: deduplicate OpencodeClient type and fix stale module comment

Export OpencodeClient interface from shared-handlers.ts and import it
in index.ts and review.ts instead of redefining inline. Also corrects
the module doc comment about /api/agents usage scope.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 23:17:16 -08:00
Michael Ramos e5f3cfffbb feat: Obsidian vault browser sidebar tab (#209)
* feat: add Obsidian vault browser sidebar tab (#207)

Add a third sidebar tab that lets users browse their Obsidian vault's
file tree, click any markdown file to open and annotate it as part of
plan feedback. Includes wikilink support for navigating between vault
files.

- New /api/reference/obsidian/files and /api/reference/obsidian/doc endpoints
- useVaultBrowser hook and VaultBrowser sidebar component
- Wikilink [[filename]] and [[filename|display]] detection in Viewer
- "Vault Browser" toggle in Settings > Obsidian
- Bare filename search for wikilink resolution within vault

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update docs and clear vault state on disable

- Add new reference endpoints to CLAUDE.md API table
- Update stale doc comments referencing "two tabs" in sidebar files
- Clear vaultPath and activeFile when vault browser is disabled

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: simplify vault browser prop passing and derived state

- Move VaultNode to packages/ui/types.ts (shared type location)
- Pass useVaultBrowser return as single object prop through SidebarContainer
- Replace showVaultTab/vaultPath useState with useMemo derivations
- Extract buildVaultDocUrl helper to deduplicate URL template
- Wrap onVaultFetchTree in useCallback
- Fix toggle switch size to match existing toggles (h-6 w-11)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 15:32:59 -08:00
Michael Ramos c7ae789a55 chore: bump version to 0.10.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-02 17:36:08 -08:00
Michael Ramos d2a159ca53 Add customizable filename format for Obsidian exports (#202)
* feat: add customizable filename format for Obsidian export (#167)

Add a filename format setting to the Obsidian integration that supports
template variables ({title}, {YYYY}, {MM}, {DD}, {Mon}, {D}, {HH}, {h},
{hh}, {mm}, {ss}, {ampm}). Default format preserves existing behavior.
Settings UI shows a live preview of the resulting filename.

https://claude.ai/code/session_01QycvXHHvAy38N36PVP3jFF

* fix: guard against double .md extension in custom filename format

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-03-02 11:21:16 -08:00
김영준E 09384361e4 fix: Fix review showing empty files + propagate diff errors to UI (#200)
* 🐛 fix: force standard a/b diff prefix to handle mnemonic prefix config

When diff.mnemonicPrefix is enabled in git config, `git diff` uses
context-dependent prefixes (c/ for commit, w/ for worktree, i/ for
index) instead of the standard a/b. Both the internal parseDiffToFiles
and @pierre/diffs library expect a/b prefixes, causing silent parse
failures that result in an empty file list.

Add --src-prefix=a/ --dst-prefix=b/ to all git diff invocations to
ensure consistent output regardless of user git configuration.

* ✨ feat: propagate git diff errors to review UI

Previously, git diff errors were silently caught and returned as empty
patches. The UI showed "No changes" with no indication of failure.

- Add error field to DiffResult and propagate through ReviewServerOptions
- Include error in /api/diff and /api/diff/switch responses
- Show distinct error state in review UI (red icon + error message)
- Clear/set error state on diff type switch

* Fix mnemonic prefix handling in pi-extension runGitDiff

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>
2026-03-01 22:26:07 -08:00
Gunit Bindal c470dcebf1 Add short URL sharing via paste service to fix URL truncation (#188)
* Add short URL sharing via paste service to fix URL truncation on Slack/messaging apps

Share URLs for large plans can be 10-40KB+ because the entire plan + annotations
are compressed into the URL hash. Services like Slack, WhatsApp, and Twitter
truncate these URLs, making shared plans unviewable (related: #142).

This adds an optional paste-service backend that stores compressed payloads and
returns short ~60-char URLs (e.g. share.plannotator.ai/p/aBcDeFgH).

Changes:
- Add Cloudflare Worker paste service (apps/paste-worker/) with KV storage
  and 90-day TTL for stored plans
- Add createShortShareUrl() and loadFromPasteId() to sharing utils
- Update useSharing hook to auto-generate short URLs with 1s debounce
- Update ExportModal to show short URL as primary copy target with
  full hash URL as backup
- Portal automatically supports /p/<id> paths via useSharing hook
- Fully backward compatible: hash-based URLs continue to work unchanged
- Graceful degradation: falls back to hash URLs if paste service is unavailable

* Fix critical bugs found during code review of short URL feature

- Worker: return only { id } so client constructs URL with its own
  shareBaseUrl (fixes self-hosted deployments)
- importFromShareUrl: handle /p/<id> short URLs in addition to hash
  URLs (fixes teammate import via short links)
- Anchor /p/<id> regex with ^ to prevent false matches on nested paths
- Pass shareBaseUrl to loadFromPasteId (was always defaulting)
- replaceState preserves base path instead of hardcoding /
- Clear stale shortShareUrl immediately on debounce to prevent showing
  outdated link during the 1s delay
- Add shareBaseUrl to dependency arrays for loadFromHash and
  importFromShareUrl callbacks
- Remove unused url field fallback from paste API response parsing

* Fix pasteApiUrl/shareBaseUrl confusion and add remote session share URLs

Bug fix (addresses @backnotprop's code review):
- useSharing hook now accepts separate `pasteApiUrl` parameter instead of
  incorrectly passing `shareBaseUrl` to `loadFromPasteId`. These are
  different domains (share portal vs paste backend). When omitted, the
  default `https://paste.plannotator.ai` is used correctly.
- Fixed in all three call sites: loadFromHash, importFromShareUrl, and
  generateShortUrl (via createShortShareUrl options).

Remote session share URLs (implements #192):
- When running on a remote instance (SSH, devcontainer), Plannotator now
  generates a share.plannotator.ai URL and prints it to stderr so the
  user can open the plan review in their local browser.
- Works for all three modes: plan review, code review, and annotate.
- Uses the same deflate-raw + base64url encoding as the client.
- Fails silently if URL generation fails — port forwarding still works.
- New server utility: packages/server/share-url.ts

* Address code review findings: fix spread limit, CORS, deps array

- share-url.ts: Replace btoa(String.fromCharCode(...compressed)) with
  a loop to avoid RangeError on plans >65K compressed bytes
- share-url.ts: Add cross-reference comment noting the server-side
  SharePayload is an intentional subset of the canonical UI type
- paste-worker: Only return CORS headers for allowed origins; disallowed
  origins get no CORS headers instead of misleading partial headers
- useSharing.ts: Remove unused shareBaseUrl from loadFromHash dependency
  array (loadFromHash only uses pasteApiUrl, not shareBaseUrl)

* Restructure paste service with pluggable storage, fix consent flow and security issues

Replaces monolithic paste-worker with multi-target paste-service architecture:
- Core logic (handler, storage interface, CORS) separated from deployment targets
- Filesystem store (self-hosted), KV store (Cloudflare), S3 stub (future)
- Bun binary target + Cloudflare Worker target
- Fix auto-upload removed: short URLs only created on explicit user click
- Clear stale short URL state when content changes
- Fix require('fs') in ESM module, add path-traversal guard in FsPasteStore
- Return 400 (not 500) for malformed JSON in both targets
- Fix compress() spread limit for large plans
- Updated docs: self-hosting guide, sharing guide, env vars, API endpoints

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Simplify paste service: extract shared router, remove TOCTOU patterns

- Extract duplicated HTTP routing from bun.ts and cloudflare.ts into
  handleRequest() in core/handler.ts — targets are now thin wrappers
- Move ID_PATTERN regex to core (was duplicated in both targets)
- Remove existsSync guard before mkdirSync({recursive:true}) in fs.ts
- Remove file.exists() check before file.json() in fs.ts get() — the
  try/catch already handles missing files
- Extract DEFAULT_SHARE_BASE constant in sharing.ts (was hardcoded twice)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Deduplicate compression, image parsing, and remote share URL logic

- Create packages/shared/ with compress/decompress (single source of truth)
  — both @plannotator/server and @plannotator/ui import from here
- Export parseShareableImages from sharing.ts, remove duplicate
  parseGlobalAttachments from useSharing.ts
- Extract writeRemoteShareLink() helper in share-url.ts, replace 3
  near-identical blocks in apps/hook/server/index.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Fix modulo bias in paste ID generation and remove nonexistent doc artifacts

- Use rejection sampling in generateId() to eliminate modulo bias
  (bytes >= 248 discarded, uniform distribution over 62 chars)
- Remove references to install-paste.sh and Docker image that don't
  exist yet; point self-hosting docs to GitHub Releases binaries

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>
2026-02-28 22:55:55 -08:00
Michael Ramos 55e91fb7a1 chore: bump version to 0.9.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:22:22 -08:00
dgrissen2 93e9420cb4 feat: open linked .md files in read-only tabs with TOC navigation (#184)
* feat: open linked .md files in read-only tabs with TOC navigation

When a plan references local .md files via markdown links, they now open
in a new browser tab using the full Plannotator viewer in read-only mode.

Changes:
- server: add /api/doc?path= endpoint with 4-strategy path resolution
  (absolute, relative to project root, bare filename search). Returns 400
  with match list on ambiguous filenames, 404 when not found, 403 on
  path traversal. Only resolves files within process.cwd().
- Viewer: detect local .md links in InlineMarkdown and route them to
  /?doc=<path>&readonly=true with a new-tab icon. Add isReadOnly prop
  that guards the web-highlighter init (prevents phantom highlights) and
  suppresses annotation toolbars.
- App: parse ?doc= URL param on load and fetch from /api/doc instead of
  /api/plan. Set isReadOnly mode which shows a read-only banner, hides
  approve/deny/feedback buttons, ModeSwitcher, Settings, AnnotationPanel,
  and annotation panel toggle. Shows an error view (not a silent fallback)
  when the document cannot be found or is ambiguous. Opens the sidebar to
  the TOC tab automatically.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: upgrade linked docs to same-view annotatable navigation with aggregated feedback

Replace the new-tab read-only approach with same-view navigation: clicking a
.md link swaps the plan content in-place, preserving all annotations via a
docCache. Users can annotate linked docs and all feedback (plan + linked docs)
is aggregated into the deny/approve payload sent to Claude.

Key changes:
- New useLinkedDoc hook for state swapping, caching, and highlight restoration
- React key on Viewer forces clean unmount/remount (fixes web-highlighter DOM crash)
- exportLinkedDocAnnotations() aggregates linked doc feedback with filepath context
- UI: 2px primary border, "Linked File" badge, "Copy file" button, TOC filepath
  indicator with back-to-plan button
- Fix Tailwind v4 cascade: move * { border-color } to @layer base so utility
  classes like border-primary actually override it
- Compact TOC spacing (padding, gaps, line-height) without affecting Version Browser
- Exclude node_modules/.git from /api/doc bare filename glob

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: harden /api/doc endpoint and align linked doc annotation output

Restrict /api/doc to .md/.mdx files only, fix heading hierarchy and
sorting in exportLinkedDocAnnotations, and update CLAUDE.md docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: complete linked doc annotations in getDocAnnotations and fix useMemo deps

- getDocAnnotations() now includes the active linked doc's live
  annotations alongside the cache, removing the implicit requirement
  to call back() before reading
- Remove unstable linkedDocHook object from annotationsOutput useMemo
  dependency array (was defeating memoization every render)
- Guard Cmd+Enter shortcut against linkedDocHook.isActive to prevent
  accidental approve/deny while viewing a linked doc

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: include linked doc annotations in approve feedback gate

The handleApprove gate only checked plan-level annotations, silently
dropping linked-doc-only feedback on "approve with notes" (OpenCode).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add getDocAnnotations to annotationsOutput useMemo deps

Ensures memo recomputes when navigating to/from linked docs, preventing
stale annotation output.

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>
2026-02-26 20:26:06 -08:00
Michael Ramos 7145f190ec Add "Open in VS Code Diff" button to plan diff viewer (#180)
* Add feature plan for VS Code diff viewer button

Scoping document for a new PlanDiffViewer button that opens
the plan diff in VS Code's native diff viewer via `code --diff`.

https://claude.ai/code/session_01FYcJkGsWfuiGy53x3pwCSW

* feat: add "Open in VS Code" button to plan diff viewer

Add a button in the PlanDiffViewer toolbar that opens the current
plan diff in VS Code's native side-by-side diff viewer. The server
writes both versions to temp files and spawns `code --diff`.

- New POST /api/plan/vscode-diff endpoint in packages/server/index.ts
- VS Code button with loading/error states in PlanDiffViewer.tsx
- Wire currentPlan/basePlan/baseVersion props from App.tsx

https://claude.ai/code/session_01FYcJkGsWfuiGy53x3pwCSW

* chore: update bun.lock after install

https://claude.ai/code/session_01FYcJkGsWfuiGy53x3pwCSW

* refactor: server reads plan versions directly instead of receiving from client

The server already has the current plan in its closure and can read
any version from disk via getPlanVersion(). No need to send plan
text from the UI — just send baseVersion.

https://claude.ai/code/session_01FYcJkGsWfuiGy53x3pwCSW

* chore: remove plan.md scoping document from repo

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: extract editor diff logic into shared packages/server/editor.ts

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: use official VS Code SVG icon in plan diff viewer button

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: use history file paths directly for VS Code diff instead of writing temp files

Both plan versions already exist on disk in ~/.plannotator/history/.
Eliminates redundant file writes, fixes UPLOAD_DIR semantic misuse,
and corrects HTTP status codes for editor errors.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: rename editor.ts to ide.ts to avoid confusion with plan editor UI

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add ide.ts and vscode-diff endpoint to CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-02-26 13:25:08 -08:00
Michael Ramos c453c6bf92 chore: bump version to 0.9.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 12:34:54 -08:00
Michael Ramos 5649e62b69 fix: remove history save logs that pollute OpenCode TUI
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 12:31:28 -08:00
Michael Ramos 01c5b92a82 chore: bump version to 0.9.1
Fix Plan Diff marketing dialog overflow on small viewports.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:55:04 -08:00
Michael Ramos d395fd522c chore: bump version to 0.9.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 00:37:31 -08:00
Michael Ramos 819ba11f77 feat: plan diff UI with sidebar and dual view modes (#176)
* feat: add plan diff UI with sidebar, badge, and dual view modes

Shows what changed between plan iterations when Claude revises after
feedback. Adds a +N/-M badge below repo info that toggles the diff view,
a shared left sidebar with TOC and Version Browser tabs, and two diff
modes: rendered (color-coded borders) and raw markdown (+/- lines).

Closes #138, closes #111

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: update CLAUDE.md project structure and align first-run dialog labels

- Add plan-diff/ and sidebar/ component subdirectories to CLAUDE.md
- Add new hooks and utils to CLAUDE.md project structure
- Rename "Table of Contents" to "Auto-open Sidebar" in UIFeaturesSetup
  to match Settings.tsx label

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address code review findings for plan diff UX

- Fix badge stats mixing block counts with line counts (modifications
  now fold into additions/deletions)
- Gate hasPreviousVersion on diffBasePlan being loaded to prevent
  "Show Changes" no-op and ModeSwitcher disappearing
- Make sidebar reactive to Settings toggle (useEffect on tocEnabled)
- Match PlanDiffViewer badge layout to Viewer (flex-col) so badge
  doesn't jump position on toggle
- Add "Exit Diff" label to the close button in diff view
- Remove dead CSS (plan-diff-removed-marker, plan-diff-modified)
- Clean up stale header comment and unused lines prop

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: second-round review cleanup for plan diff UX

- Fix stale "amber border" JSDoc in PlanCleanDiffView (actually green)
- Rename sidebar tab from "diff" to "versions" for clarity
- Gate VersionBrowser fetch on versionInfo being available
- Move .sidebar-tab-flag CSS into its own Sidebar section

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add loading state for version selection in sidebar

Add isSelectingVersion to selectBaseVersion, mirroring the existing
isLoadingVersions pattern. Shows "Loading..." on the selected version
button while the fetch is in progress.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: address third-round code review findings

- Fix duplicate border/backdrop on TOC inside sidebar (className override)
- Fix loading indicator targeting wrong version button (fetchingVersion state)
- Fix "Show Changes" button silent no-op (gate on hasPreviousVersion)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: move date to slug suffix, improve Other Plans UX

- Slug format changed from YYYY-MM-DD-{heading} to {heading}-YYYY-MM-DD
- Other Plans: single "coming soon" banner instead of per-item labels
- Strip date suffix from plan names in sidebar for readability
- Remove cursor-not-allowed from Other Plans items

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add Plan Diff section to CLAUDE.md, alert on version fetch failure

- Document plan diff feature: engine, view modes, state management, sidebar
- Update slug format documentation to {heading}-YYYY-MM-DD
- Show native alert when version fetch fails instead of silent swallow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: add table rendering to clean diff view

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 18:59:44 -08:00
Michael Ramos bf9a15a185 feat: add plan version history backend and API (#175)
* feat: add plan version history (backend + API)

Save plan versions to ~/.plannotator/history/{project}/{slug}/ on every
plan arrival. Serves previousPlan and versionInfo via /api/plan, and adds
GET /api/plan/version?v=N for fetching any historical version. Enables
future diff UI. Deduplicates identical resubmissions.

Closes #138, closes #111

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* feat: add version listing and project history APIs

Add GET /api/plan/versions to list all versions of the current plan with
timestamps, and GET /api/plan/history to list all plans in the current
project. Both endpoints available in shared server and pi extension.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs: add version history section and API endpoints to CLAUDE.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 11:36:18 -08:00
Michael Ramos 444934a654 refactor: rename diff → annotations in plan review context (#173)
* refactor: rename misleading "diff" terminology to "annotations" in plan review context

The plan review flow used "diff" naming (exportDiff, diffOutput, .diff.md,
"Raw Diff", "Download .diff") for what is actually user annotations/feedback
on a plan. This was confusing since the code review flow legitimately uses
"diff" for actual git diffs. Renames all plan-review-context "diff" references
to "annotations" across code, UI labels, file extensions, and docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: update stale exportDiff references in ANNOTATE.md

Missed during the diff→annotations rename. Updates two references
to exportDiff() → exportAnnotations() in the annotate flow docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: rename remaining "Download Diff" label and tab type in App.tsx

The quick-save dropdown button still showed "Download Diff" and the
initialExportTab state type still used 'diff' instead of 'annotations'.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 09:11:25 -08:00
Michael Ramos 4492cd8988 chore: bump version to 0.8.5
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:22:23 -08:00
Michael Ramos ca507166f6 chore: bump version to 0.8.4
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 12:18:01 -08:00
Michael Ramos a4651dede8 chore: bump version to 0.8.3
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-21 11:55:45 -08:00
Dor Tzur b2fc5ab849 fix(server): prevent arbitrary file read via /api/image endpoint (#164)
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]
2026-02-18 09:50:32 -08:00
Michael Ramos 6a2e7dbd74 chore: bump version to 0.8.2
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 08:24:39 -08:00
rerorero bf0596443e fix(browser): use open -a only for PLANNOTATOR_BROWSER on macOS (#163)
* 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>
2026-02-18 08:12:39 -08:00
Michael Ramos 35de9756a0 chore: bump version to 0.8.1
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 07:51:23 -08:00
Michael Ramos 13b427b97b feat: use BROWSER env var as fallback for opening UI (#153)
* 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>
2026-02-16 12:03:59 -08:00
Michael Ramos 6f3bfde039 chore: bump version to 0.8.0
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-13 14:05:27 -08:00