212 Commits

Author SHA1 Message Date
Michael Ramos b545969b00 chore: bump version to 0.14.5
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-23 00:06:38 -07:00
Dillon Mulroy 0d13d208a8 fix: remove duplicate 'Code Review' header in pi extension review feedback (#370)
exportReviewFeedback() already includes a '# Code Review Feedback' header
in its output. The pi extension was wrapping that output with another
'# Code Review Feedback' prefix, causing the heading to appear twice
when submitting review feedback.

Remove the redundant header from sendUserMessage() so the pre-formatted
feedback is sent directly.

Add tests verifying exportReviewFeedback output contains exactly one
top-level heading, preventing future regressions.
2026-03-22 20:42:00 -07:00
Michael Ramos 40002e69dc feat: GitLab merge request review support (#364)
* feat: GitLab merge request review support

Add full GitLab MR review parity with existing GitHub PR review:

- Auto-detect platform from URL (github.com vs any GitLab host)
- Extract GitHub logic into pr-github.ts, new pr-gitlab.ts implementation
- Widen PRRef/PRMetadata to discriminated unions for type safety
- Dispatch functions route to correct platform implementation
- Platform-aware UI labels (PR/MR, #/!, GitHub/GitLab icons)
- Self-hosted GitLab support via --hostname flag
- Normalize glab diff output to standard git format
- Handle glab CLI differences (no --jq, Content-Type header for --input)
- Defensive JSON parsing for GitLab context API responses

Tested against gitlab.com with inline comments, multi-line ranges,
approval, and PR context tabs (summary, comments, checks).

For provenance purposes, this commit was AI assisted.

* fix: correct GitLab enum mappings and add shared file path encoding

- Map GitLab job statuses to UI-expected enums (failed→FAILURE, canceled→NEUTRAL)
- Map GitLab detailed_merge_status to CLEAN/BLOCKED/BEHIND/DIRTY/UNKNOWN
- Fix false approval state on repos without required approvers
- Add shared encodeApiFilePath helper used by both GitHub and GitLab

For provenance purposes, this commit was AI assisted.

* fix: align panel headers and refine file tree selection style

- Use shared --panel-header-h CSS variable for consistent header heights
  across file tree search, file header, and annotations panel
- Update GitLab icon to use official tanuki SVG paths with currentColor
- Replace solid primary fill on active file tree items with 30% tinted
  background for better readability and semantic color preservation

For provenance purposes, this commit was AI assisted.
2026-03-22 10:22:36 -07:00
Michael Ramos c5204770d2 chore: bump version to 0.14.4
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:37:28 -07:00
Michael Ramos 181e23711a fix: eliminate gaps around file header in code review
Move FileHeader out of the scroll container into a flex-col wrapper so
it spans the full panel width. Make resize handles zero-width overlays
instead of layout-occupying flex children.

Closes #354

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 17:36:37 -07:00
Rock Neurotiko c352465254 feat: Approve and review PR to github (#352)
* Approve and review PR to github

* fix: GitHub review improvements — multi-line ranges, own-PR detection, error handling

- Add start_line/start_side to review payload for multi-line annotations
- Detect current GitHub user and disable Approve on own PRs with tooltip
- Fix loading state: approve button no longer shows "Approving..." during feedback
- Fix empty submit: block Post Comments when no annotations and no comment
- Fix Cmd+Enter in GitHub comment dialog
- Fix completion screen text for GitHub mode ("submitted to GitHub")
- Fix agent label fallback to "Your agent" instead of "OpenCode"
- Improve gh-not-installed error message with install URL
- Fix stale useCallback dependency array on handleGitHubAction

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

* feat(review): destination dropdown, icon components, and UI polish

Replace Agent/GitHub toggle with a compact destination dropdown.
Buttons stay consistent ("Send Feedback"/"Post Comments" + "Approve")
with behavior routed by destination. Double-tap Option to toggle.

- Add GitHubIcon, RepoIcon, PullRequestIcon components (currentColor)
- Add repo/PR icons to editor header
- Add keyboard hint in destination dropdown
- Add double-Option shortcut to settings
- Hide duplicate filename from Pierre diff header
- Refine FileHeader typography (text-xs font-semibold, no mono)

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

* fix: include VS Code editor annotations in GitHub PR reviews

Editor annotations were silently dropped when submitting to GitHub.
Now converts them to inline PR comments with selected text as context.

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

* fix: rename visibility, own-PR keyboard guard, and editor annotation filtering

- Keep data-prev-name visible in Pierre header for rename diffs
- Block Cmd+Enter approve path for own PRs (was only blocked via mouse)
- Filter editor annotations to diff files only to prevent GitHub API rejection

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

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-20 16:48:26 -07:00
Michael Ramos 33d5d6154c fix: prevent resize handle from covering scrollbar (#359)
* fix: prevent resize handle touch area from covering scrollbar (#354)

The ResizeHandle touch target extended 8px in both directions (-inset-x-2),
overlapping the 6px scrollbar on the adjacent content area. Users could see
the scrollbar but couldn't grab it because the resize handle intercepted clicks.

Add a `side` prop so the touch area only extends outward (away from the scroll
container) — left handles extend left, right handles extend right.

Closes #354

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

* fix: remove transform/opacity from global transition to fix choppy scroll

The global `*` rule applied 150ms transitions on transform and opacity to
every DOM element. During scroll, the compositor fights these transitions
on sticky headers, annotation highlights, and layer compositing — causing
visible choppiness.

Narrowed to color, background-color, border-color, box-shadow only. These
handle theme switching and hover states without affecting scroll performance.
Components needing transform/opacity transitions already declare their own
via Tailwind classes (205 usages across 45 files).

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-20 16:11:06 -07:00
Brian Malinconico 7ed85dfe0b fix(parser): support nested markdown code fences (#355)
* fix(parser): support nested markdown code fences

Count backticks in the opening fence and only close on a line with at
least that many backticks. Previously any ``` line would prematurely
close a 4- or 5-backtick fence, corrupting blocks that embed markdown
examples. Follows CommonMark §4.5.

Adds parser.test.ts with 6 tests covering the fix and baseline
triple-backtick behaviour. Also adds devbox.json to pin bun for
running tests.

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

* chore(devbox): wire up test script to bun test

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

* fix(parser): pass raw line to closingFence regex; add edge-case tests

The regex already anchors trailing whitespace with \s*$ so calling
.trim() before testing was redundant. Passing the raw line is also
more correct — it lets the regex reject a closing fence indented more
than three spaces (CommonMark §4.5 semantics), not that the rest of
the parser handles indented blocks today, but the intent is clearer.

Also adds three previously untested edge cases:
- Unclosed fence at EOF (extends to end of document per spec)
- Fence opener as the last line (zero-content block, no crash)
- toHaveLength(1) guard on the language-tag preservation test

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

* Overcomit

* Overcomit

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 12:03:24 -07:00
Vincent Hardouin 29f09d3288 feat: show repo identifier in tab title (#342) (#353)
* feat: show repo identifier in tab title (#342)

* fix: fallback title when repoInfo is null
2026-03-20 09:31:41 -07:00
Michael Ramos d0ebca45eb chore: bump version to 0.14.3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 23:45:54 -07:00
Michael Ramos 1821943d06 feat(review): PR context panel — summary, comments, and checks (#350)
* feat(review): add PR context panel with summary, comments, and checks tabs

When reviewing a GitHub PR, the ReviewPanel now shows icon tabs for
Summary (PR body, labels, linked issues), Comments (chronological
thread of comments + reviews), and Checks (CI status, merge readiness).
Tabs only appear in PR mode; local review is unchanged.

Data fetched lazily via new /api/pr-context endpoint on first tab click.
Uses DOMPurify for safe HTML rendering of GitHub markdown content.
Inline markdown renderer extended with link and bare URL support.

Closes #348

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

* fix(review): reset fetch guard on error and detect inline HTML in PR bodies

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-19 23:14:21 -07:00
Michael Ramos 0908e234e1 feat(review): VS Code-style diff search in file tree sidebar (#347)
* feat(review): add diff search engine and highlight utilities

Search data layer for code review: patch parser, match finder, file
grouping, snippet extraction, DOM highlight injection with shadow DOM
traversal, and state management hook.

Co-Authored-By: sercan tor <tor.sercan@gmail.com>

* feat(review): wire search into file tree sidebar

VS Code-style search UI in the file tree panel. Search input at the top
of the sidebar replaces the tree with grouped results when active.
Clicking a match navigates to the file and scrolls to the line.

Keyboard: Cmd/Ctrl+F focuses input, Enter/F3 steps through matches,
Escape clears. In-diff highlights via shadow DOM traversal.

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

* fix(review): correct highlight assignment for duplicate matches and trimmed queries

Group search matches by line before highlighting so each DOM occurrence
gets the correct match ID. Also trim the query before building the
highlight regex to stay consistent with the search engine.

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

---------

Co-authored-by: sercan tor <tor.sercan@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 19:28:13 -07:00
Michael Ramos ac4d03e069 chore: bump version to 0.14.2
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-19 10:45:40 -07:00
Michael Ramos b632131aac chore: bump version to 0.14.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:35:59 -07:00
Michael Ramos 1df5f40eb7 feat: persist viewed files in code review drafts (#332) (#335)
Extend the draft auto-save system to include viewed file state alongside
annotations. Viewed files are saved atomically in the same draft file,
restored together via the same banner, and backward compatible with
existing drafts (optional field, defaults to empty).

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 16:28:54 -07:00
Michael Ramos d5b6bc702b fix: single submit_plan with text/path auto-detect for OpenCode (#333)
* fix: restore uniform submit_plan and add submit_plan_file for OpenCode

PR #318 replaced the original text-based submit_plan with a file-path-only
version and split prompt injection between plan/non-plan agents. This caused
regressions: the agent couldn't figure out file paths from non-plan agents,
and the 80+ line prompt with TodoWrite replacements was fragile against
OpenCode upstream changes.

This restores the original submit_plan(plan) that accepts markdown text
directly — the contract that worked uniformly across all agents — and keeps
the file-based workflow as submit_plan_file(path) for users who want
persistent plan files.

Key changes:
- Two tools: submit_plan (text) + submit_plan_file (path)
- Unified prompt for all primary agents (not just plan mode)
- Removed aggressive TodoWrite string replacements and system-reminder
- Kept adversarial stripping of OpenCode's STRICTLY FORBIDDEN rules
- Extracted shared server helpers to reduce duplication

Addresses #328

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

* fix: single submit_plan with auto-detect text/path for OpenCode

Collapses submit_plan + submit_plan_file back into one tool that
auto-detects whether the argument is plan text or a file path.

First submission: agent passes markdown text (simple, works from any agent).
On deny: response includes the history path where the plan was saved, so the
agent can Edit the file for targeted revisions and resubmit with the path.

Key changes:
- One tool: submit_plan(plan) accepts text or absolute .md file path
- Server surfaces historyPath through waitForDecision (already saved by
  saveToHistory, just not returned before)
- Deny response includes file path hint for Edit-based revision workflow
- Unified prompt for all primary agents (~25 lines, no TodoWrite warfare)
- Still strips OpenCode's STRICTLY FORBIDDEN rules and suppresses plan_exit

Addresses #328 and rcdailey's feedback on PR #333

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

* fix: remove historyPath leak, error on missing file paths, restore two-tier prompt

- Remove historyPath from deny flow — internal history directory should not
  be exposed to agents. Text submissions get text feedback; file submissions
  get file feedback. No crossover.
- Error when agent passes an absolute .md path that doesn't exist instead of
  silently treating it as plan text.
- Restore two-tier prompt: plan agent gets full planning instructions, other
  primary agents get a minimal reminder (matching pre-v0.13.0 behavior).
- Clean up stale prompt copy referencing historyPath-based revision flow.

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

* fix: restore todowrite override, strengthen planning prompt, remove noisy logs

- Override todowrite description to defer to submit_plan during active planning
- Tool description now instructs agent to explore and ask questions before submitting
- Sequenced planning prompt: explore, ask, then write
- Remove success logs from integration saves (stderr was bleeding through)
- Append resubmit reminder to OpenCode deny feedback

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-18 15:31:29 -07:00
Marcelo Terreiro Prado 9056e18af7 fix: preserve slashes in Bear tag normalization for nested tags (#331) 2026-03-18 09:07:10 -07:00
Michael Ramos 54d50f8beb chore: bump version to 0.14.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 07:53:39 -07:00
Michael Ramos 216815c12e feat: PR review support via GitHub URL (#324)
* 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>
2026-03-18 06:01:40 -07:00
Michael Ramos 6b775ea1ed feat: /plannotator-last — annotate the last agent message (#325)
* feat: add /plannotator-last command to annotate last assistant message

Adds a new slash command that extracts the last rendered assistant message
from Claude Code's session log and opens it in the annotation UI.

Session log parser (apps/hook/server/session-log.ts):
- Parses Claude Code JSONL logs at ~/.claude/projects/{slug}/*.jsonl
- Finds the last assistant message.id with text content blocks
- Skips noise entries (progress, system, file-history-snapshot, queue-operation)
- Filters system-generated user messages by prefix to avoid false turn boundaries
- Walks backward through empty turns when back-to-back user messages exist
- No anchoring — reads from end of log since <command-message> isn't written
  until after the binary completes

New files:
- apps/hook/commands/plannotator-last.md — slash command definition
- apps/hook/server/session-log.ts — Claude-Code-specific log parser
- apps/hook/server/session-log.test.ts — 30 tests covering streaming chunks,
  tool call turns, sub-agent noise, stop hooks, thinking blocks, and edge cases

Modified:
- apps/hook/server/index.ts — annotate-last subcommand

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

* chore: remove 3 redundant real-world scenario tests

These duplicated coverage already provided by focused unit tests:
- "full conversation" → covered by "grabs last message.id in multi-tool turn"
- "stop hook interrupted" → covered by "skips progress and system noise"
- "long tool-only sequence" → covered by "skips tool-only assistant entries"

Kept the thinking block test (unique coverage). 27 tests remain.

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

* feat: add /plannotator-last command to Pi extension

Uses Pi's session manager API to find the last assistant message —
walks backward through ctx.sessionManager.getEntries(), finds the
last entry with role "assistant" and text content, opens it in the
annotation UI. Reuses existing isAssistantMessage(), getTextContent(),
startAnnotateServer(), and runBrowserReview() from the extension.

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

* feat: add /plannotator-last to OpenCode plugin + extract command handlers

Adds annotate-last command that fetches session messages via
client.session.messages(), finds the last assistant message with text
parts, and opens it in the annotation UI.

Refactors command handling: extracts review, annotate, and annotate-last
handlers from the inline event hook into commands.ts module. Reduces
index.ts by ~120 lines and makes adding future commands cleaner.

New files:
- apps/opencode-plugin/commands.ts — extracted command handlers
- apps/opencode-plugin/commands/plannotator-last.md — command metadata

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

* feat: context-aware UI labels for annotate-last mode

Adds "annotate-last" mode to the annotate server, passed through to the
UI via /api/plan response. The editor uses this to show "Copy message"
instead of "Copy plan", and "annotations on the message" in the
completion overlay.

- packages/server/annotate.ts: new `mode` option on AnnotateServerOptions
- packages/editor/App.tsx: annotateSource state derived from mode
- packages/ui/components/Viewer.tsx: copyLabel prop for button text
- All three harnesses pass mode: "annotate-last" in their callers

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

* feat: add Codex support to annotate-last command

Detects Codex via CODEX_THREAD_ID env var (injected by Codex into every
spawned process). Uses the thread ID to find the rollout file in
~/.codex/sessions/, parses the Codex rollout JSONL format to extract
the last assistant message.

Also adds `plannotator last` alias for shorter usage in Codex bang
commands (!plannotator last).

New files:
- apps/hook/server/codex-session.ts — Codex rollout parser
- apps/hook/server/codex-session.test.ts — 9 tests

Modified:
- apps/hook/server/index.ts — Codex detection + `last` alias

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

* fix: context-aware feedback title + top spacing for paragraph-first content

- exportAnnotations now accepts a title param: "Message Feedback" for
  annotate-last, "File Feedback" for file annotation, "Plan Feedback"
  for plan review (default)
- Adds top spacer when content starts with a paragraph (not a heading)
  and has no frontmatter, fixing tight spacing in annotate-last mode

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

* chore: add sandbox scripts for Pi and Codex testing

- sandbox-pi.sh: builds extension, creates temp project, installs via
  `pi install`, launches Pi with sample files
- sandbox-codex.sh: compiles binary, creates temp project, launches
  Codex. Test with `!plannotator last`

Both follow the same pattern as sandbox-opencode.sh.

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

* fix: add hook build step to opencode sandbox script

The opencode build copies HTML from hook/dist/ — without building hook
first, the sandbox could use stale HTML. Pi and Codex sandboxes already
had this step.

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

* fix: remove command body from plannotator-last to prevent agent response

The .md body was being sent to the agent as a prompt, causing it to
respond with "Opening annotation UI..." before the event handler could
fetch messages. That response became the "last message" instead of the
actual one. Empty body = agent stays silent, event handler intercepts.

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

* fix: use command.execute.before hook for OpenCode annotate-last

Moves plannotator-last from the passive event hook to the
command.execute.before hook. This intercepts the command before the
agent sees it, clears output.parts so the agent stays silent, fetches
session messages, opens the annotation UI, then sends feedback via
client.session.prompt() — same pattern as review/annotate.

Previously the agent would respond to the command body before the
event handler could fetch messages, polluting the session history.

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

* fix: add Codex to origin type and agent name mapping

Origin "codex" was falling through to the default "Coding Agent" label.
Added "codex" to the origin union type across annotate server, editor,
and removed the `as any` cast in the hook.

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

* fix: remote share link, plan-specific prose, and codex type unions

- Add writeRemoteShareLink to annotate-last onReady callback so remote
  sessions get a reachable URL
- Add subject parameter to exportAnnotations so feedback says "message"
  or "file" instead of "plan" when appropriate
- Add 'codex' to origin type unions in useAgents, Settings, UpdateBanner,
  and App.tsx fetch handler

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

* fix: correct JSDoc for projectSlugFromCwd (leading dash is kept, not stripped)

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

* refactor: use RenderedMessage type instead of inline structural type

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-17 23:49:34 -07:00
Jared Wyce 9e760fb973 fix: opencode review cwd context flow (#323)
* fix opencode review cwd context flow

* fix: sync pi-extension review-core with shared cwd changes

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

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 17:29:09 -07:00
Barbaros G. b4eb37f981 fix: proxy race condition + IPC discovery for VS Code SSH Remote (#321) (#322)
* fix: add retry + auto-reload to VS Code proxy for SSH race condition (#321)

When opening plannotator over VS Code SSH Remote, the webview could show
a "proxy error" because the cookie proxy connected before the upstream
Bun server was ready. Two layers of defense:

1. Retry with exponential backoff (200/400/800ms) in the cookie proxy,
   buffering the request body so retries can replay it
2. Silent iframe auto-reload in the webview wrapper if no "ready" signal
   is received within 3 seconds (max 1 reload to prevent loops)

Bump vscode extension to 0.5.2.

* fix: file-based IPC registry for VS Code extension discovery (#321)

VS Code's environmentVariableCollection only injects PLANNOTATOR_BROWSER
into interactive terminal shells — background processes spawned by Claude
Code hooks don't inherit it. In SSH Remote sessions this meant
openBrowser() was never called (handleServerReady skipped it when
isRemote=true and PLANNOTATOR_BROWSER was unset).

- Extension writes IPC port to ~/.plannotator/vscode-ipc.json keyed by
  workspace path; cleans up on deactivate
- openBrowser() falls back to IPC registry when shell-based open fails,
  using longest-prefix workspace match for multi-window support
- handleServerReady() always calls openBrowser() since the IPC fallback
  handles the remote case
2026-03-17 09:37:55 -07:00
insects f29dbbb1f8 fix(review): disable external diff in git commands (#320) 2026-03-17 09:17:14 -07:00
Michael Ramos 03390eb2c9 chore: bump version to 0.13.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 16:43:09 -07:00
Michael Ramos fc655beb0e feat: Pi-style iterative planning for OpenCode plugin (#318)
* feat: extract checklist utilities to shared package

Move ChecklistItem, parseChecklist, extractDoneSteps, and
markCompletedSteps from Pi extension to @plannotator/shared
for reuse by the OpenCode plugin.

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

* feat: Pi-style iterative planning for OpenCode plugin

Rewrite the OpenCode plugin to match Pi's planning methodology:

- Inject rich iterative planning prompt when agent is "plan"
  (explore → update plan → ask user loop, structured plan format)
- File-based submit_plan: reads plan from disk instead of requiring
  it as a string arg. Resolves path from OpenCode's system prompt,
  falls back to PLAN.md
- Suppress plan_exit via tool.definition hook (directs to submit_plan)
- Add PLANNOTATOR_ALLOW_SUBAGENTS env var for #289
- Pass planFilePath to denial feedback template
- Keep existing subagent/build/title guards intact

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

* fix: address review findings in OpenCode plugin

- Cache agents list (static per session, was fetched every LLM call)
- Remove TOCTOU: drop redundant file.exists() before file.text()
- Eliminate duplicate system.join() by reusing joined string
- Resolve getSharingEnabled() once in submit_plan instead of twice
- Use path.join() instead of string concatenation for file paths

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

* feat: session-scoped plan files and tool-neutral prompt

Replace plugin-global resolvedPlanFilePath and prompt-path parsing with
per-session plan files at ~/.plannotator/session-plans/opencode/{id}/plan.md.
Remove resolvePlanFilePath() regex (fixes spaces-in-path and cross-session
race). Make planning prompt tool-neutral (no write/edit references) so it
works with apply_patch models. Strip OpenCode's native read-only and
experimental-mode prompt lines before injecting Plannotator's planning prompt.

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

* feat: directory-based plan storage with path validation

Replace session-scoped plan files with a shared plan directory at
~/.plannotator/session-plans/opencode/. Agent picks the filename,
submit_plan takes a path arg and validates it (absolute, inside plan
dir, exists, readable, non-empty) with canonical path checks to
defeat traversal and symlink escapes. Remove summary and plan string
args. Planning prompt is now tool-neutral and directs the agent to
reuse the same file on feedback, not create new ones.

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

* fix: use OpenCode's native plans directory for permission compatibility

OpenCode's plan mode permission ruleset only allows edits to
.opencode/plans/*.md and $XDG_DATA_HOME/opencode/plans/*.md.
Our custom ~/.plannotator/session-plans/opencode/ path was blocked
by PermissionDeniedError at the tool level regardless of prompt
stripping. Switch to the XDG path that OpenCode already allows.

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

* feat: exploration-first planning prompt

Restructure the planning prompt as a phased workflow:
Explore → Ask → Write → Submit. The agent now explores the
codebase before creating a plan file or asking questions,
producing better-researched plans for existing codebases.
Greenfield tasks can skip straight to questions.

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

* chore: fix stale path in JSDoc header comment

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-16 16:13:57 -07:00
Michael Ramos 459a1f4946 fix: guard Obsidian mkdir against Bun EEXIST regression (#319)
Bun v1.1.43–1.1.45 throws EEXIST on mkdirSync with recursive:true
when the directory already exists. Add existsSync guard to prevent
save failures when the Obsidian folder already exists.

Fixes #315
2026-03-16 12:39:53 -07:00
Michael Ramos f31f6728f5 chore: bump version to 0.13.0
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 08:43:13 -07:00
Michael Ramos 4a38c65bc6 fix: unify favicon background color to dark navy
The server-side inline SVG still had the original purple (#6B3FA0)
while the marketing site favicon was updated to dark navy (#070b14).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 08:43:08 -07:00
Michael Ramos f2f713a655 fix: truncate git error messages in code review UI
Git dumps its entire --help output on some failures (e.g. running
code review from a non-git directory). The error was passed raw to
the UI, rendering hundreds of lines of usage text. Extract only the
first meaningful line and cap at 200 chars. Also add line-clamp on
the UI error display as a safety net.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-16 08:43:03 -07:00
Michael Ramos ea689d9745 Unify review core across Bun and Pi (#310)
* Unify review core across Bun and Pi

* Surface review diff failures

* fix: review core fixes from code review

- Handle unborn HEAD in runGitDiff("uncommitted") via rev-parse check
  instead of assertGitSuccess, so fresh repos fall through to untracked diffs
- Bind Pi server to 0.0.0.0 for remote sessions (regression from e47eda0)
- Update CLAUDE.md: packages/shared/ description, PLANNOTATOR_SHARE env var,
  /api/diff response shape

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

* fix: update favicon background to dark navy

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-16 07:55:15 -07:00
dgrissen2 01d807787b feat: add favicon (Purple P + gold highlight) (#312)
* feat: add favicon (option 2 — purple P with gold highlight)

Adds the "Purple P + Highlight" favicon across all three Plannotator
servers (plan, review, annotate). The icon is a rounded purple square
with a bold white "P" and a semi-transparent gold stripe through the
middle — typographic, on-brand, and legible at 16px.

Implementation:
- shared-handlers.ts: handleFavicon() serves the inline SVG with a
  1-day cache header, shared by all servers
- index.ts, review.ts, annotate.ts: /favicon.svg route added before
  the SPA catch-all
- apps/hook/index.html, apps/review/index.html: <link rel="icon">
  added pointing to /favicon.svg

SVG favicons are the modern standard and render crisply at all sizes
without a separate .ico file.

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

* feat: add favicon to marketing site

Use the same purple P + gold highlight SVG favicon on plannotator.ai.

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

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-03-16 07:45:00 -07:00
Michael Ramos 93c0f035b3 feat: annotatable diff view with diff context in feedback
* refactor: extract useAnnotationHighlighter hook from Viewer

Move annotation plumbing (web-highlighter lifecycle, toolbar/popover
state, text-selection handlers, findTextInDOM, applyAnnotations) out
of Viewer.tsx into a dedicated hook. Pure refactor — zero behavior
change. Viewer consumes the hook and keeps its own code block, global
comment, and pinpoint-specific logic.

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

* feat: block-level diff annotation with diffContext support

Add annotation support to plan diff view using block-level hover.
Hovering added/removed/modified sections shows the annotation toolbar.
No web-highlighter in diff mode — annotations live in React state only.

- diffContext field on Annotation type (added/removed/modified)
- PlanCleanDiffView: hover handlers, toolbar, comment/quicklabel flows
- Annotated blocks show persistent highlight ring via content matching
- View isolation: diff annotations filtered to diff view, normal to normal
- Share/draft restore filters diff annotations from Viewer DOM
- AnnotationPanel: neutral "diff" badge for diff annotations
- Export: [In diff content] label in feedback
- Toolstrip visible during diff mode for mode switching
- CLAUDE.md updated

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

* fix: scroll-to-selected and visible highlight ring for diff annotations

Add scroll-to-selected when clicking a diff annotation in the panel —
scrolls to the block and briefly glows (same focused effect as Viewer).
Replace invisible ring-1 ring-primary/20 with ring-2 ring-accent for
annotated blocks so they're visually distinct.

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

* cleanup: memoize annotation filters, fix timer leaks, use blockId for highlight rings

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

* fix: preserve normal annotations across diff toggle

Replace ternary rendering with display:none so the Viewer
stays mounted and web-highlighter DOM marks survive the toggle.

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

* fix: store full block content in diff annotations instead of truncating to 500 chars

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-15 23:47:35 -07:00
Michael Ramos bb4aab27c4 fix: tater sprite z-index regression from mobile compat PR (#308)
* fix: tater sprite running behind plan document instead of in front

Move TaterSpriteRunning inside the z-0 content wrapper stacking context
so it layers correctly: above sidebars (z-auto) but below the plan
document (z-10). The mobile compat PR (#260) added relative z-0 to the
content wrapper, which trapped the plan at z-0 while the sprite at z-40
floated above everything.


* fix: move z-10 from main to inner content so sprite runs above grid
2026-03-15 22:33:22 -07:00
Michael Ramos d5e0ff6fe6 feat: Octarine notes integration + auto-save for all integrations (#297)
* feat: Octarine notes integration + auto-save for all integrations

Add Octarine as a third notes app integration alongside Obsidian and Bear.
Uses the octarine:// URI scheme to create notes via deep links, following
the same x-callback-url pattern as Bear.

- New file: packages/ui/utils/octarine.ts (cookie-backed settings)
- Server: saveToOctarine() in integrations.ts, wired into /api/approve
  and /api/save-notes endpoints
- UI: Octarine tab in Settings, card in Export > Notes, dropdown button,
  Cmd+S shortcut support
- Parallelize all integration saves with Promise.allSettled (was sequential)
- Add auto-save on plan arrival toggle to Bear and Octarine (Obsidian
  already had this), consolidate into a single effect + single API call

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

* feat: add YAML frontmatter properties to Octarine notes

Prepend Octarine-compatible YAML frontmatter with tags, Status, Author,
and Last Edited properties. Uses the same extractTags() as Obsidian for
auto-generated tags (project name, title words, code fence languages).

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

* fix: use fresh=true for Octarine saves to prevent content duplication

Octarine's create action appends by default. If auto-save fires on plan
arrival and the user then approves within the same minute, the same path
gets hit twice — doubling the content. Using fresh=true replaces instead.

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

* fix: trim workspace and folder in saveToOctarine before building URI

The UI checks workspace.trim().length > 0 but the server used raw values.
Accidental whitespace in settings would cause Octarine saves to fail.

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

* fix: use isOctarineConfigured() for client-side Octarine guards

Auto-save and approve checks used raw workspace truthiness, so
whitespace-only workspace would trigger a save attempt that the server
rejects. Now uses isOctarineConfigured() which trims before checking.

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

* fix: prevent Bear duplicate notes and align default-save dropdown gates

Bear creates a new note on every save, so skip it on approve when
arrival auto-save already succeeded. Gate the default-save dropdown
by actual configuration (vault path for Obsidian, workspace for
Octarine) instead of just the enabled toggle, matching the shortcut
behavior. Self-heal stale defaults back to "ask".

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-15 21:07:01 -07:00
Michael Ramos 908ea9cf32 refactor: shared feedback templates + preserve plan title on deny (#296) (#298)
* refactor: shared feedback templates across all integrations

The deny/feedback prompts sent to LLM agents were duplicated as inline
string templates in hook, opencode-plugin, and pi-extension — each with
different tone and framing. The hook's directive style (from #224) was
the most effective at getting agents to address feedback. This extracts
all feedback text into @plannotator/shared/feedback-templates and has
every integration import from the single source of truth.

Closes #215 follow-up (propagates fix to OpenCode and Pi).

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

* test: rewrite feedback template tests around contracts not implementation

Tests now verify: cross-integration consistency, verbatim feedback
preservation, empty input handling, and that approved messages don't
contain directive language. Wording can change freely without breaking
tests.

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

* fix: instruct agent to preserve plan title on resubmission (#296)

Version history slugs are derived from the plan's first # heading.
When the agent renames the heading after a deny, the version chain
breaks and the user loses diffs. The deny template now tells the
agent not to change the title unless explicitly asked.

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

* style: improve plan deny preamble readability

Break the dense single-paragraph preamble into structured sections:
verdict, directive, and rules list. Easier for agents to parse.

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

* fix: add missing @plannotator/shared workspace dependency

Hook and OpenCode plugin imported from @plannotator/shared/feedback-templates
without declaring it as a dependency. Worked locally but failed in CI.

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

* revert: remove code review and annotate from shared templates

Scope-crept into code review/annotate feedback which introduced a double
heading regression and dropped integration-specific strings. Reverts those
paths to their original inline strings; shared module now only covers
plan deny feedback.

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

* fix: restore Pi plan file hint and vendor template for source installs

Add optional planFilePath to planDenyFeedback so Pi can tell the agent
to read the plan file before editing. Check in a vendored copy of the
template so Pi source installs work without running build:pi first.

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-15 19:38:22 -07:00
sercan tor 6cde39507b feat: add file-scoped comments to /plannotator-review (#303)
* feat(review): add file-scoped comments in code review (#302)

* refactor: reuse CommentPopover for file comment form

Replace the custom popover implementation in FileHeader (~88 lines of
hand-rolled state, click-outside, and escape handling) with the existing
CommentPopover component from packages/ui. This gives us expand-to-dialog
mode, image attachments, scroll-aware positioning, and keyboard shortcuts
for free, while saving ~62 net lines.

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

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-15 14:58:48 -07:00
Michael Ramos e1bd27aae4 feat: custom theme system with 18 built-in themes (#294)
* 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>
2026-03-14 21:26:51 -07:00
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
Itay Grubman 7817c46d71 fix: suppress native mobile context menu on text selection (#281) 2026-03-12 16:15: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
Michael Ramos 7417f49076 feat: add new settings indicator for Plan Width and Quick Labels
Pulsing dot on the Settings gear button and "new" pill badges on the
Display and Labels tabs signal newly added settings. Dismissed on first
open via cookie-based version gating.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 01:04:00 -07:00
Michael Ramos fbd4ee4f06 Remove non-critical welcome dialogs (#280)
* chore: remove non-critical welcome dialogs

Remove UI Features Setup, Plan Diff Marketing, and What's New v0.11.0
dialogs from the first-run cascade. Only the Permission Mode Setup
dialog remains as it's the only one that affects agent behavior.

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

* refactor: extract demo plan content to separate file

Moves the 334-line PLAN_CONTENT string from App.tsx to demoPlan.ts to reduce clutter.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 00:27:16 -07:00
Michael Ramos 0ad1cce653 chore: move demo diagram sections below SQL code block
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-11 23:44:12 -07:00
Itay Grubman 9a23c249b2 feat: add quick label selection mode for one-click annotations (#272)
* feat: add quick annotation labels for one-click preset feedback

Add preset label chips (Needs tests, Security concern, Break this up, etc.)
that allow instant annotation without typing. Includes ⚡ toolbar button,
Alt+1..8 keyboard shortcuts, label customization in Settings, and label
summary in export output.

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

* feat: add quick label selection mode for one-click annotations

* feat: redesign quick label picker UX and add label tips

- Redesign FloatingQuickLabelPicker as a vertical context-menu style list
  with cursor-anchored positioning (appears at mouseup point, not selection center)
- Unify label dropdown: toolbar and quick-label mode now share the same
  FloatingQuickLabelPicker component (removed duplicate InlineQuickLabelDropdown)
- Fix above/below flip positioning (follow CommentPopover pattern with
  conditional translateY)
- Add label tips: optional instruction text on QuickLabel that gets injected
  into agent feedback as a blockquote below the label
- Add tip editor in Settings with three visual states (empty/editing/filled)
- Add "Missing overview" default label with a tip for requesting narrative context
- Extend keyboard shortcuts from Alt+1-8 to Alt+1-9
- Suppress input method toggle (Alt) when label picker is open
- Reorder default labels: Clarify this, Needs tests, Consider edge cases,
  Missing overview, Security concern, Break this up, Wrong order, Discuss first,
  Nice approach

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

* feat: curate default labels, add cyan/amber colors, bare digit shortcuts

Finalize the 10 default quick labels based on user feedback data:
clarify, overview, verify, example, patterns, alternatives, regression,
out-of-scope, tests, nice-approach. Each label gets a unique color
(added cyan and amber to the palette). Bare digit keys (1-0) now apply
labels when the picker is open, Alt+N still works everywhere. Tip editor
cursor starts at beginning for readability.

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

* fix: prevent duplicate annotation when digit key fires both toolbar and picker handlers

When the quick label picker is open from the toolbar's zap button,
let FloatingQuickLabelPicker own all keyboard input instead of both
components handling the same keypress.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-03-11 23:39:46 -07:00
김영준E e51abc6fd5 feat: render diagrams by default in plan review (#279) 2026-03-11 23:13:01 -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
Itay Grubman c0076621ac feat: add quick annotation labels for one-click preset feedback (#268)
Add preset label chips (Needs tests, Security concern, Break this up, etc.)
that allow instant annotation without typing. Includes ⚡ toolbar button,
Alt+1..8 keyboard shortcuts, label customization in Settings, and label
summary in export output.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-03-11 16:49:30 -07:00
Itay Grubman 5437a37da9 feat: add mobile compatibility (#260)
* feat: add mobile compatibility

- Add responsive hamburger menu with all header actions (MobileMenu)
- Annotation panel renders as full-screen overlay on mobile with backdrop and close button
- Panel starts closed on mobile (<768px)
- Touch support for resize handles, pinpoint annotations, and toolstrip buttons
- Mobile text selection creates annotations via highlighter.fromRange() bridge
- Card action buttons always visible on touch devices (hover:none media query)
- Settings modal uses horizontal tab bar on mobile
- CommentPopover width capped to viewport on small screens
- Replace mousedown with pointerdown for touch-compatible click-outside handling
- Add useIsMobile reactive hook for breakpoint detection
- Desktop layout (>=768px) unchanged

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

* fix: mobile layout polish — panel gap, button overlap, responsive labels

- AnnotationPanel: fix bottom gap on mobile overlay (inset-y-12 → top-12 bottom-0)
- Viewer: push in-plan action buttons below badges on mobile (mt-6), add
  clear-right before frontmatter, show short labels (Comment/Copy) on mobile
- App: reduce mobile horizontal padding to 8px (px-2)
- test-hook.sh: build review before hook to fix missing dist error

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

* feat: add plan width display setting with compact/default/wide options

Adds a configurable plan width preference (compact 832px, default 1040px,
wide 1280px) with an abstract layout preview in Settings. Dynamic max-width
flows through to Viewer, PlanDiffViewer, and the toolstrip. Default is
compact to preserve existing behavior.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-03-11 16:25:48 -07:00