Commit Graph

231 Commits

Author SHA1 Message Date
Oscar Silva f08764063d feat(review): support multi-repo workspace reviews (#543)
* feat(review): support multi-repo workspace reviews (#527)

* fix(workspace): address critical issues from deep review

- Fix race condition in label generation by pre-computing labels sequentially
- Fix rewritePatchLine to support quoted paths and rename/copy headers
- Add separator between aggregated patches to avoid invalid diffs
- Normalize input paths in resolveWorkspaceFilePath
- Add timeout to PR discovery (15s) to prevent server hangs
- Fix PATCH /api/workspace/repo to rollback state on failure via applyRepoMutation
- Validate body.source runtime (must be 'local' or 'pr')
- Snapshot active repo in agent jobs at launch to prevent race in onJobComplete
- Prevent double-prefixing of agent findings when paths are already prefixed
- Fix frontend findWorkspaceRepoForPath to use longest-prefix matching
- Fix shared types: diffType uses DiffType, platformUser is string | null

* fix: remove duplicate gitRuntime export in vcs.ts

* fix: resolve remaining merge conflict in local review mode, remove stale detectManagedVcs import

* Add local multi-repo workspace review support

* Fix workspace review edge cases

* Remove session query from browser launch

* Add switchable workspace review modes

* fix(review): cover opencode workspace bridge

* fix(review): clean workspace review plumbing

* fix(review): clarify workspace agent finding paths

* fix(review): preserve diff paths with spaces

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-06-05 14:29:38 -07:00
Michael Ramos 26ca4e0275 Single-source skills (core/extra), replace Claude Code commands with skills, de-hardcode installers (#850)
* feat: single-source skills into core/extra, replace Claude commands with skills, de-hardcode installers

- apps/skills/core/{review,annotate,last,archive}: single authoritative
  source for the always-installed skills (archive is new); all carry
  disable-model-invocation + agents/openai.yaml sidecars
- apps/skills/extra/{compound,setup-goal,visual-explainer}: no longer
  default-installed (except Kiro); installers print an
  `npx skills add backnotprop/plannotator/apps/skills/extra` suggestion
- Claude Code: apps/hook/commands/ deleted, command heredocs removed;
  core skills in ~/.claude/skills are the slash commands now
- Installers: OpenCode/Gemini command files copied from an extended
  sparse checkout instead of heredocs; install.cmd gains the previously
  missing OpenCode command install; aggressive cleanup of legacy
  ~/.claude/commands and ~/.codex/skills artifacts
- Codex: core skills install to ~/.agents/skills (official path);
  ~/.codex/skills install removed
- Pi: extension no longer bundles skills; #670 settings filter removed

* fix: review findings — old-tag soft guards, cmd replace-not-merge, plugin-update hint, frontmatter test

- install.sh: a --version tag predating apps/skills/core no longer aborts
  the whole copy subshell (which also skipped OpenCode/Gemini commands);
  core skills now soft-skip with an accurate message, matching ps1/cmd
- install.sh: subshell failure message no longer claims "git required"
  when git was present (clone/network errors get their own wording)
- install.cmd: pre-remove skill dirs before xcopy so upgrades replace
  rather than merge (stale files from renamed/deleted skill files no
  longer linger; parity with sh/ps1)
- all installers + docs: tell upgraders to run /plugin marketplace update
  so the plugin's old namespaced plannotator:* commands disappear (#817)
- install.test.ts: assert every core SKILL.md sets
  disable-model-invocation: true — the load-bearing line that keeps core
  skills out of Pi's system prompt (#842 regression guard)

* test: pin old-tag soft-guard behavior, dedupe core-skill list in tests

* fix: interrogation review findings — cross-installer diagnostic parity

- install.ps1/install.cmd: emit the "predates the core/extra skill
  layout" diagnostic on old pinned tags instead of silently skipping
  core skills (parity with install.sh)
- install.ps1: clone/network failure no longer claims "git required"
  (git was already verified present); the outer catch now reports the
  actual exception
- install.sh: "Installed OpenCode/Gemini commands" echoes are guarded
  on the copy actually having a source, so old pinned tags don't print
  false success (ps1/cmd already gated this way)
- AGENTS.md: opencode-plugin commands/ comment now reflects all four
  command stubs
- install.test.ts: shared test asserts the soft-skip diagnostic exists
  in all three installers and pins ps1's honest failure wording

* fix: respect CODEX_HOME for Codex home directory (#852)

Codex stores config and state under $CODEX_HOME when set, falling back
to ~/.codex (developers.openai.com/codex/config-advanced). Plannotator
hardcoded ~/.codex in two places:

- runtime: codex-session.ts scanned ~/.codex/sessions for rollout
  files, so `plannotator last` failed with "No rendered assistant
  message found" when CODEX_HOME pointed elsewhere. Now resolved the
  same way copilot-session.ts handles COPILOT_HOME and session-log.ts
  handles CLAUDE_CONFIG_DIR.
- installers: detection, config.toml/hooks.json paths, manual-setup
  instructions, and the stale-skills cleanup now derive from
  CODEX_HOME in all three scripts.

Tests: codex-session.test.ts covers rollout discovery under a
CODEX_HOME temp dir; install.test.ts asserts all three installers
respect the variable and that the fallback is the only hardcoded
~/.codex path left in install.sh.

* fix: hard-fail skill install, guard command cleanup, one-time extras migration

External review triage on PR #850 surfaced two real installer issues:

P1 — commands deleted before replacement: the Claude command cleanup
ran before the git-gated skill install, so a missing git, a failed
clone, or an old pinned tag deleted the user's slash commands and
installed nothing (a regression — the old installer needed no git).
Now:
- missing git is a hard failure before anything is touched ("install
  git, then run this installer again")
- a failed fetch is a hard failure ("something went wrong — run the
  installer again") instead of a silent skip
- the legacy command cleanup runs AFTER the install and only removes a
  command file when its same-name replacement skill exists on disk
- old pinned tags keep the soft-skip (no deletion happens, commands
  survive, CI e2e against old tags stays green)

P2 — recurring extras deletion: the extras cleanup ran on every
invocation, deleting copies users reinstalled via the suggested
`npx skills add` (the copies are byte-identical, so only provenance
can tell them apart). The cleanup is now a one-time migration recorded
in a migrations ledger under the Plannotator data dir
(<PLANNOTATOR_DATA_DIR|~/.plannotator>/migrations/), the same
record-what-you-did pattern package managers use.

All three installers (sh/ps1/cmd) updated in parity; tests pin the
guard condition, the ledger gating, and the hard-fail messages.

* test: tripwire — install.cmd must never contain /dev/null redirects

* fix: every skill sets disable-model-invocation — no exceptions

Maintainer rule: all Plannotator skills are user-invoked, never
model-auto-invoked. setup-goal (missing since #665) and the three Kiro
skills now carry the flag. The frontmatter test scans every SKILL.md in
apps/skills/core, apps/skills/extra, and apps/kiro-cli/skills
dynamically — with a floor of 10 — so a future skill cannot ship
without it.

* docs: git is a hard installer requirement; clarify post-gate sections complete on re-run

* docs: align ps1/cmd comments with hard-fail semantics

* feat: guided install — extras opt-in via skills CLI, model-invocation picker

Interactive terminals get a two-question wizard on first run:
1. Install the extra skills? Yes delegates to `npx skills add
   backnotprop/plannotator/apps/skills/extra` (its UI picks the agents),
   wired to /dev/tty so piped curl|bash installs still work. Skipped
   when extras already exist on disk.
2. Make any skills callable by the model? Yes opens a space-toggle
   checkbox (sh/ps1) or numbered toggles (cmd), listing all skills if
   extras were chosen, core-only otherwise. Chosen skills get
   disable-model-invocation stripped from their INSTALLED copies and the
   Codex sidecar's allow_implicit_invocation flipped — re-applied every
   run since installs replace skill folders. Repo sources stay locked.

Answers persist to <data dir>/install-prefs (shared format across all
three installers) and re-runs reuse them silently; --reconfigure
re-opens the wizard. Automation is untouched: no terminal means no
prompts and today's defaults; --extras/--no-extras/--model-invocable/
--non-interactive give scripts explicit control.

* fix: self-review of guided install — cmd pipe expansion bug, flag/wizard interplay

- install.cmd: the checkbox preselection used `echo !var! | findstr` —
  each side of a cmd pipe runs in a child WITHOUT delayed expansion, so
  the saved choices passed through as literal !var! text and
  preselection never matched. Replaced with a substring-replace
  containment test (no pipe).
- all three: a wizard question whose answer was already provided by a
  CLI flag (--extras/--no-extras/--model-invocable) is no longer asked
  and then silently overridden — the flag pre-answers it.
- install.cmd: unknown-option usage line now lists the wizard flags.

* feat: guided install question 3 — install Glimpse (native window)

glimpseui (third-party npm package, PR #840) gives Plannotator a native
WebView window instead of a browser tab; the runtime already
auto-detects it on PATH, so a global install is all that's needed.

- Wizard asks "Install Glimpse?" (default yes) after the skills
  questions; skipped when glimpseui is already on PATH
- Yes runs `npm install -g glimpseui` (bun fallback on sh/ps1; printed
  instruction when neither exists) — wizard or explicit flag only,
  silent re-runs never install software
- --glimpse / --no-glimpse flags for automation; choice persisted to
  install-prefs like the others
- docs + tests updated (glimpse detection, install command, flags, and
  persist-condition assertions across all three installers)

* fix: self-review of Glimpse question — cmd bun fallback, stale usage text

* fix: merge-window hardening — guard Codex cleanup, remove old-installer junk dirs

plannotator.ai serves install.sh live from main (public/ symlink,
deployed on push), while the script fetches repo files at the LATEST
RELEASE TAG. Between merging the core/extra restructure and cutting the
release that ships it, the live script runs against the old-layout tag.
Two hazards in that window:

1. The Codex stale-skill cleanup removed working ~/.codex/skills with
   no successor installed (core skills soft-skip on old tags). Now the
   cleanup runs AFTER the install and removes a core skill only once
   its replacement exists in ~/.agents/skills — same guard the Claude
   command cleanup uses. The compound/setup-goal stale copies stay
   unconditional (never Codex's to begin with).

2. The reverse combo (cached OLD script + NEW release tag) wholesale-
   copies apps/skills/* and leaves junk core/ and extra/ directory
   copies in ~/.claude/skills. Never valid skill names — all three
   installers now remove them on every run.

* fix: glimpseui is a devDependency — consumers never use it from node_modules

PR #840 added glimpseui to dependencies in @plannotator/server and
@plannotator/pi-extension, but nothing imports it: both runtimes detect
the CLI on PATH (Bun.which / a manual PATH walk) and spawn it. The dep
only ever mattered in repo development, where `bun run` prepends
node_modules/.bin to PATH. For consumers it was inert download weight —
OpenCode plugin installs and `pi install` pulled a third-party package
that could never be detected (Pi's loader does not expose
node_modules/.bin; verified). Moved to devDependencies in both: dev
flows keep working, published packages stop shipping it. The sanctioned
end-user path is the guided installer's global `npm install -g
glimpseui`.

* fix: clean stale plugin command files from the installed plugin checkout (#817)

The installer already manages hooks.json inside
~/.claude/plugins/marketplaces/plannotator/apps/hook/, so the earlier
"don't reach into plugin storage" rationale for leaving the old
namespaced plannotator:* command files there was inconsistent. All
three installers now remove them — same replacement-skill guard as the
bare ~/.claude/commands cleanup — making the #817 duplicate menu
entries die on a single installer run + restart instead of waiting for
/plugin marketplace update. Hints/docs reworded accordingly.

* Revert "fix: clean stale plugin command files from the installed plugin checkout (#817)"

This reverts commit 3df37da92c.

* fix: Windows CI — assert the new no-commands contract; gate cmd wizard on a real console

The cmd e2e CI step still asserted the OLD contract (installer writes
~/.claude/commands/plannotator-*.md with the ! prefix). Commands are
dead; the step now guards the NEW contract: a fresh install must write
NO plannotator command files. The Gemini TOML assertions stay — they
now verify the verbatim checkout copy delivers intact files (the tag
the e2e pins, v0.17.1, contains apps/gemini/commands).

The failure also exposed that install.cmd ran the wizard on redirected
stdin (set /p falls through to defaults at EOF) — and Q3's default
being yes meant CI silently ran `npm install -g glimpseui`. cmd now
probes for a real console via `timeout /t 0` (errors when stdin is
redirected), matching sh's /dev/tty and ps1's IsInputRedirected gates:
no console, no wizard, no wizard-only installs.
2026-06-05 09:23:45 -07:00
Oleksii Nikiforov 3bde235a85 fix(server): launch Glimpse via node on Windows instead of unspawnable npm shim (#861)
On Windows, Bun.which("glimpseui") resolves to an npm script shim (.cmd / extensionless shebang), which spawn() cannot launch without a shell: it throws EINVAL on .cmd and ENOENT on the shim, so openGlimpse() always returned false and plannotator fell back to the browser. shell:true is not viable because it severs the stdin HTML pipe (glimpse.mjs then exits 1). Resolve the package entry and run it with node directly instead.
2026-06-05 08:52:33 -07:00
Michael Ramos b2b8ce8090 chore: bump version to 0.19.27
For provenance purposes, this commit was AI assisted.
2026-06-03 14:32:40 -07:00
Michael Ramos ac2630078f feat: add PLANNOTATOR_GLIMPSE env var to disable Glimpse native window
Add glimpse config option to PlannotatorConfig and resolveUseGlimpse()
resolver. Wire into both Bun and Pi browser-opening paths. Document
PLANNOTATOR_GLIMPSE, PLANNOTATOR_GLIMPSE_WIDTH, and
PLANNOTATOR_GLIMPSE_HEIGHT in env var reference and AGENTS.md.

For provenance purposes, this commit was AI assisted.
2026-06-03 14:19:31 -07:00
Graham Lipsman be2c81fa3b annotate-last: pick which message to annotate (fixes #800) (#809)
* feat: message picker for annotate-last (#800)

When running /plannotator-last after /rewind, the newest transcript
entry is no longer the message the user intended to annotate, and there
was no affordance to pick a different one.

Adds a picker UI that surfaces the recent assistant messages so the
user can choose which one to annotate:

- A "Message N of M" button in the Viewer's sticky-top action bar
  (alongside Copy / Global comment / Attachments), so it stays
  accessible while scrolling.
- A "Messages" tab in the left sidebar with the full list
  (newest-first, preview + timestamp, default ★), mirroring the
  existing Files / Versions / Archive tab pattern.

Wired for Claude Code, Codex, and Droid (all share apps/hook/server).
OpenCode, Pi, and Copilot still get the original single-message
behavior — they don't emit recentMessages, so the picker affordances
hide cleanly.

Default selection (index 0) matches today's "last message" behavior,
so users who don't interact with the picker see no change.

* feat: extend annotate-last picker to Copilot and OpenCode

The picker UI from #800 was wired for Claude / Codex / Droid only. Pull
Copilot and OpenCode onto the same shape so users on those harnesses
also get the recent-messages picker when annotating the last assistant
message.

- Copilot: replace getLastCopilotMessage with getRecentCopilotMessages,
  walking events.jsonl newest-first up to 25 assistant.message events.
- OpenCode: rewrite the session walk to collect up to 25 messages
  (newest first) instead of bailing on the first hit; normalize the SDK
  time.created (ms epoch) to ISO to match the shared picker contract.
- Both pass recentMessages to startAnnotateServer only when length > 1,
  matching the existing Claude/Codex/Droid behavior.

Also trims a leftover narrating comment in MessagesBrowser and refreshes
the stale Copilot session-parser header.

Pi parity follows in the next commit (needs round-trip of the picker
selection through /api/feedback so its post-submit anchoring quotes the
right message).

* feat(pi): wire annotate-last picker with feedback round-trip

Extends the picker UI (#800) to Pi and fixes a Pi-specific anchoring bug
the picker would otherwise introduce.

Picker plumbing
- assistant-message: getRecentAssistantMessages walks the active branch
  newest-first, returning { messageId, text, timestamp? } in the same
  shape the other harnesses produce.
- Plumbed through plannotator-browser / plannotator-events so the Bun
  server's recentMessages option is populated when the branch has more
  than one assistant message.

Anchoring fix
- Pi quotes the targeted assistant message back to the agent because its
  UX is async — the conversation may have moved on by feedback time.
  With the picker, that target is no longer guaranteed to be the
  snapshot taken when the UI opened. The editor now sends the user's
  selectedMessageId with /api/feedback; Pi looks it up in the current
  branch via findAssistantMessageByEntryId and quotes that message
  instead. Falls back to the original snapshot if the entry is gone.
- The round-trip field is optional and only meaningful in annotate-last
  mode; other harnesses (and other modes) ignore it.

Timestamp safety
- Pi's SDK currently types SessionEntryBase.timestamp as string, but the
  picker contract everywhere else is ISO. Treat the value as unknown and
  normalize string/number(ms)/Date to ISO; drop anything else, rather
  than blind-casting and risking silent drift if the SDK changes.

* chore: strip issue-number references from comments

Comments shouldn't rely on external references — issue numbers age out
of context, link rot is a thing, and a reader shouldn't need to open
GitHub to understand why a line exists. Strip the `(#800)` and `(#570)`
parentheticals from comments and doc strings across the picker and
review-gate code; the surrounding "why" content is preserved.

* fix: prevent removeChild crash when switching annotate-last messages

Switching the picked message remounted nothing, so React reconciled new
content against DOM that web-highlighter had mutated with <mark> nodes,
throwing removeChild. Drive the Viewer key (and StickyHeaderLane's
remount token) off a shared viewerContentKey so a message switch fully
remounts the Viewer and re-anchors the sticky-header observer.

Also cap MessagesBrowser row previews via previewText() and drop the
redundant 'block' class that was overriding line-clamp-2.

* feat: persist annotate-last feedback across messages

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-06-03 13:01:36 -07:00
Benjamin Jesuiter 96aad592af Open Plannotator in Glimpse when available (#840)
* feat: open plannotator in glimpse

* fix: harden Glimpse browser integration

* chore: refresh lockfile after rebase

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-06-03 12:17:11 -07:00
Michael Ramos d8e0b86f96 chore: bump version to 0.19.26
For provenance purposes, this commit was AI assisted.
2026-05-31 20:12:19 -07:00
Michael Ramos 3638190844 chore: bump version to 0.19.25
For provenance purposes, this commit was AI assisted.
2026-05-31 19:19:56 -07:00
Michael Ramos d479106038 chore: bump version to 0.19.24
For provenance purposes, this commit was AI assisted.
2026-05-27 22:22:49 -07:00
Michael Ramos 8c947c5419 Add Amp plugin integration (#803)
* Add Amp plugin integration

* Use official Amp logo on landing page

* Tighten landing agent selector

* Default landing selector to Claude Code

* Stabilize server ready handoff test

* Create ready handoff directory before writing

* Stabilize server ready handoff tests

* Fix Amp command cancellation and cwd

* Preserve Plannotator browser handling for Amp

* Fix Amp review edge cases

* Add PowerShell installer smoke coverage
2026-05-27 21:49:30 -07:00
Hrand Liu e0aee7451b feat: add PLANNOTATOR_DATA_DIR env var to customize data directory (#795)
* feat: add PLANNOTATOR_DATA_DIR env var to customize data directory

* fix: update missed hardcoded paths to use PLANNOTATOR_DATA_DIR

OpenCode plugin and VS Code extension still used hardcoded
~/.plannotator paths, causing the IPC registry and plan backing
file to diverge from the server when PLANNOTATOR_DATA_DIR is set.

Also exports data-dir from @plannotator/shared and documents the
new env var in AGENTS.md.

Co-authored-by: Chris Werner Rau <14326070+cwrau@users.noreply.github.com>
Co-authored-by: João O. Santos <34689526+Joao-O-Santos@users.noreply.github.com>

* fix: vendor data-dir.ts into Pi extension and rewrite imports

The Pi extension copies shared/server modules into generated/ at
build time. Without vendoring data-dir.ts and rewriting the
parent-relative imports, typecheck fails on all generated files
that import getPlannotatorDataDir.

* refactor: eliminate duplicated data-dir logic and clean up call sites

- VS Code extension: replace inlined getPlannotatorDataDir() copy with
  import from the canonical packages/shared/data-dir.ts (esbuild bundles
  it, so no runtime dependency needed)
- storage.ts: hoist repeated getPlannotatorDataDir() calls to a
  module-level DATA_DIR constant, matching the pattern config.ts uses
- data-dir.ts: remove inaccurate docstring claim about relative path
  resolution (the code does not call resolve())
- improvement-hooks.ts: hoist to DATA_DIR constant, clarify comments
  on the two-level hook lookup (hooks/ subdir vs root fallback)

* fix: resolve relative PLANNOTATOR_DATA_DIR to absolute path

A relative value like ./data would break readArchivedPlan's path
traversal guard, which compares a resolve()'d absolute path against
the still-relative planDir prefix. Always return an absolute path
so all callers get consistent path shapes.

* fix: use @plannotator/shared/data-dir imports in server package

Switch from relative ../shared/data-dir imports to the package
export, matching the convention every other server file follows.
Update Pi vendor script sed rules to match the new import style.

* fix: use package imports in server and respect data dir in compound skill

Server modules: switch from relative ../shared/data-dir imports to
@plannotator/shared/data-dir, matching the convention every other
server file follows. Update Pi vendor script sed rules to match.

Compound skill: update hardcoded ~/.plannotator paths to check
PLANNOTATOR_DATA_DIR first, so the skill reads plans and writes
the improvement hook to the correct location when users set a
custom data directory.

Co-authored-by: Chris Werner Rau <14326070+cwrau@users.noreply.github.com>
Co-authored-by: João O. Santos <34689526+Joao-O-Santos@users.noreply.github.com>

* fix: remove remaining hardcoded ~/.plannotator assumptions

- Settings UI: replace hardcoded path in label and placeholder with
  generic text that doesn't assume a specific data directory
- quickLabels: update agent tip to reference PLANNOTATOR_DATA_DIR
  so the agent checks the correct plans directory
- codex-review: hoist getPlannotatorDataDir() to module-level DATA_DIR
  constant, eliminating redundant per-call resolution in debugLog()
- Tests: make submit-plan and storage tests resilient to
  PLANNOTATOR_DATA_DIR being set in the environment
- Install scripts (sh, ps1, cmd): check PLANNOTATOR_DATA_DIR before
  falling back to ~/.plannotator for config.json attestation lookup

* fix: expand tilde in install script and update test assertions

install.sh: PLANNOTATOR_DATA_DIR set to ~/... stays literal inside
double quotes, so the config file check silently failed. Add case
statement to expand ~ the same way the runtime data-dir.ts does.

install.test.ts: update three assertions that checked for hardcoded
~/.plannotator paths — now verify PLANNOTATOR_DATA_DIR awareness
instead.

* docs: add PLANNOTATOR_DATA_DIR to env var reference with VS Code note

Document the new env var on the marketing site's environment
variables reference page. Include a footnote about ensuring
VS Code inherits the variable when launched from the Dock.

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
Co-authored-by: Chris Werner Rau <14326070+cwrau@users.noreply.github.com>
Co-authored-by: João O. Santos <34689526+Joao-O-Santos@users.noreply.github.com>
2026-05-26 14:56:07 -07:00
Michael Ramos 17c808cdca chore: bump version to 0.19.23
For provenance purposes, this commit was AI assisted.
2026-05-25 12:29:50 -07:00
Michael Ramos 7db5e9b8d9 Fix Windows Pi shim spawning (#792)
* Fix Windows Pi shim spawning

* Fix Pi smoke process cleanup

* Kill Windows Pi process trees
2026-05-25 11:50:50 -07:00
Michael Ramos 6254a3c181 chore: bump version to 0.19.22
For provenance purposes, this commit was AI assisted.
2026-05-23 23:30:57 -07:00
Michael Ramos 4db7fcc5da chore: bump version to 0.19.21
For provenance purposes, this commit was AI assisted.
2026-05-21 01:56:04 -07:00
Michael Ramos 2a5528693f Add Ask AI to plan and annotate reviews (#763)
* Add Ask AI to plan and annotate reviews

- mount shared AI runtime on plan, annotate, review, and Pi servers

- add shared document chat UI and comment-popover Ask AI entry point

- default providers from detected agent origin and document first-run announcement

- reuse shared code-review AI hook and document setup/docs

* Address Ask AI review followups

Stabilize AI chat session resets and callbacks, preserve per-origin provider defaults, share AI chat formatting utilities, and avoid blocking startup on model discovery.

* Fix AI permission details and Pi CLI lookup

Show formatted tool input in document AI permission cards and make Pi AI provider CLI detection work on Windows.

* Fix Pi model discovery in AI capabilities

Keep AI runtime startup non-blocking while making the capabilities endpoint await pending Pi/OpenCode model discovery before returning provider metadata.
2026-05-21 01:32:17 -07:00
Michael Ramos fa4482d7d5 chore: bump version to 0.19.20
For provenance purposes, this commit was AI assisted.
2026-05-19 08:30:48 -07:00
Yoni Hornstein 42c85f0add fix(browser): treat no-op BROWSER values as unset so headless sessions can fall back (#756)
Claude Code's agent view (and similar background/headless environments) sets
$BROWSER=true to mean "do not launch a browser." The previous logic took that
literally and ran `true http://localhost:NNNN` via `Bun.$`, which exits 0 without
opening anything. The server then sits forever in waitForDecision() with no
visible UI and no way for the user to recover the URL.

Detect the documented no-op sentinels (`true`, `false`, `none`, `:`, `0`, `1`)
on both PLANNOTATOR_BROWSER and BROWSER and treat them as if the variable were
unset. This lets shouldTryRemoteBrowserFallback() reach the VS Code IPC
fallback in remote sessions and lets openBrowser() fall through to the
platform default when nothing else is configured.

Refs #154.
2026-05-19 08:03:49 -07:00
Michael Ramos 82636e1286 Add interactive goal setup UI (#731)
* Add interactive goal setup UI

* Refine goal interview skip and question flow

* Fix review findings: recommendation combo, option-only recs, single deselect

* Persist goal setup working JSON files

* Refine goal setup copy and facts controls

* Remove generated goal package from PR

* Address goal setup review issues

* Remove goal setup slash command adapters

* Disable fact comment attachments

* Fix goal setup fact comment state

* Address goal setup review cleanup

* Fix goal setup fact submission edge cases
2026-05-18 08:39:29 -07:00
Michael Ramos f471ebf99e chore: bump version to 0.19.18
For provenance purposes, this commit was AI assisted.
2026-05-17 23:53:11 -07:00
Michael Ramos 9fed785141 chore: bump version to 0.19.17
For provenance purposes, this commit was AI assisted.
2026-05-14 17:36:52 -07:00
Michael Ramos 12e3e2d35b chore: bump version to 0.19.16
For provenance purposes, this commit was AI assisted.
2026-05-13 12:42:12 -07:00
Michael Ramos 95750ab657 feat: search-based code navigation with peek view (#711)
* feat: search-based code navigation with peek view (#694)

Add IDE-like code navigation to the review UI. Cmd/Ctrl+click a token
in a diff to find its definitions and references across the repo via
ripgrep, displayed in a VS Code-style peek panel below the diff.

Backend: bounded rg search with language-aware definition patterns
(TS/JS, Python, Go, Rust), ranked results (same file > changed files >
same directory), confidence labels, and graceful degradation when rg
is not installed. Both Bun and Pi servers implement the endpoints.

Frontend: Dockview peek panel with syntax-highlighted full-file preview
on the left and grouped reference list on the right. Clicking a
reference scrolls the preview; double-clicking an in-diff result
navigates to the file with a gold line flash.

Closes #694

* fix: resolve Pi server TypeScript errors for code-nav

Add missing spawn import, type the close callback parameter,
and use double-cast for parseBody → CodeNavRequest.

* fix: clear loading state on cached preview hits

Without this, clicking a cached file while a fetch is in-flight
leaves isLoading stuck true — the spinner hides the preview.

* feat: show pointer cursor on Cmd/Ctrl+hover for navigable tokens

Adds pn-token-nav class with thicker underline and pointer cursor
when hovering a token while holding the modifier key, signaling
the token is Cmd+clickable for code navigation.

* refactor: remove go-to-diff navigation from peek panel

Strip the in-diff badge, double-click-to-jump, highlightDiffLine
wiring, and onCodeNavGoToDiff from the peek panel. The peek view
is the primary interaction — jump-to-diff adds complexity without
clear value at this stage.

* chore: remove dead code from code-nav cleanup

Delete unused highlightDiffLine.ts, remove codeNavChangedFiles
and codeNavActiveSide from context and App.tsx, drop stale
extractChangedFiles import.

* chore: add code-nav endpoints to AGENTS.md, remove dead activeSide state

* fix: don't classify bare indented calls as definitions

Change the TS/JS method pattern from zero-or-more (*) to
one-or-more (+) declaration keywords, so plain calls like
startServer(config) are no longer misclassified as definitions.

* feat: show toast when code-nav is unavailable in platform-only PR mode

Instead of opening the peek panel and showing misleading "No results",
Cmd+click in non-local PR mode shows a brief toast explaining that
code navigation requires a local checkout.

* fix: strip hljs hardcoded background from code-nav preview

The highlight.js github-dark theme sets a fixed dark background
on all .hljs elements. Apply transparent override for the entire
peek preview so code inherits the active theme's background.
2026-05-13 12:24:37 -07:00
Michael Ramos 32e871415f chore: bump version to 0.19.15
For provenance purposes, this commit was AI assisted.
2026-05-13 08:18:34 -07:00
Michael Ramos 3fb0b9cf03 fix(gitlab): persist unposted inline comments + split pr-provider from browser-safe pr-types (#719)
Closes #680. Two changes that landed together because the persistence fix
exposed a hidden architectural constraint.

1. GitLab inline comments: when one or more discussion POSTs failed
   (e.g. transient `i/o timeout`), the failed comment bodies were lost.
   Now `submitGlMRReview` writes them to
   `~/.plannotator/failed-comments/{host}-{project}-mr{iid}-{ts}.json`
   in both the all-fail and partial-fail branches. The throw-vs-warn
   split is preserved deliberately: all-fail throws so the UI retries
   from a clean state, partial-fail warns so the UI doesn't resubmit
   already-posted content.

2. Split `packages/shared/pr-provider.ts` into `pr-types.ts`
   (browser-safe types + pure label/URL helpers) and `pr-provider.ts`
   (server-only dispatch that imports pr-github / pr-gitlab). The
   review-editor browser bundle previously dragged pr-gitlab.ts in as
   dead code via static imports, which silently constrained the file
   to never use Node built-ins. Adding `fs`/`os`/`path` for (1) broke
   the review build until we routed browser imports to pr-types and
   left server callers on the now server-only pr-provider facade.

Server-only `pr-provider.ts` re-exports `pr-types` so existing
server-side imports keep working unchanged.
2026-05-13 05:27:28 -07:00
Michael Ramos d21d0de074 fix: accept PLANNOTATOR_PORT=0 without spurious warning (#716)
Port 0 is the conventional "let OS pick a random port" value and is
already the local-mode default. Validation rejected it as invalid and
printed a warning, even though the fallback returned 0 anyway.

Fixes #715
2026-05-13 04:51:56 -07:00
Michael Ramos 4c8338f53f feat(ui): copyable hook path + guidance in Settings Hooks tab (#707)
* feat(ui): show copyable file path and guidance in Hooks settings tab

Always return the improvement hook file path from /api/hooks/status
(actual path when present, expected path when absent) so the UI can
display it in both states. Add CopyPathButton with tilde-shortened
display and full-path clipboard copy. When active, guide users to
edit directly or regenerate via /plannotator-compound. When absent,
show expected path and both creation options (auto-generate or manual).

* fix(ui): anchor displayPath on .plannotator instead of guessing homedir

The regex assumed home directories are always two segments deep
(/Users/x), which breaks for /root on Linux — it would capture
/root/.plannotator as the home prefix and display ~/hooks/... instead
of ~/.plannotator/hooks/..., leading users to create the file in the
wrong location.
2026-05-11 21:07:58 -07:00
Madhu C.S. 4272312eb0 Add jj evolog diff mode to code review UI (#702)
* review: add jj evolog diff mode to code review UI

Adds a new "Evolution diff" diff type for jj repos that shows what
changed between two evolutions (amendments) of the current change — i.e.
what was amended since a prior state of `@`.

Changes:
- Add `JjEvoLogEntry` type to `review-core.ts` and export from
  `shared/types.ts`
- Add `getJjEvoLogEntries()` to `jj-core.ts` — runs `jj evolog` with a
  tab-delimited template to collect commit ID, description, and age for
  each historical state of `@`
- Add `jj-evolog` to the `DiffType` union in `review-core.ts` and to the
  `JJ_DIFF_TYPES` set in `vcs-core.ts`
- Wire evolog mode into `runJjDiff()` and `getJjDiffArgs()` — defaults
  to the second evolog entry (the most recent prior state) when no
  explicit base is given; propagates `error` when there's no history
- Expose `jjEvologs` on `GitContext` and include the "Evolution diff"
  option in `diffOptions` only when two or more entries exist
- Add `EvoLogPicker.tsx`: a Radix Popover component that lists evolog
  entries and lets the user pick which prior state to compare against;
  shows commit ID, description, and age with a "default" badge on the
  auto-selected entry
- Update `FileTree.tsx` to render `EvoLogPicker` instead of
  `BaseBranchPicker` when `jj-evolog` is the active diff type
- Update `App.tsx` to thread `jjEvologs` and `detectedEvoBase` through
  to the file tree, auto-set the base to the second evolog entry on mode
  switch, and show an appropriate empty-state message
- Update `agent-review-message.ts` with an inspect hint for the evolog
  diff type
- Add unit tests covering: diff args, evolog output parsing, error
  cases, and the auto-base-selection fallback path

* review: fix evolog picker overflow and add evolog test sandbox

Fix the EvoLogPicker trigger and popover rows to handle narrow sidebar
widths — age strings now truncate instead of bleeding out of the container.

Add --with-evolog flag to the JJ manual test sandbox that amends the
working-copy change four times to create realistic evolution history.
Also writes a create-evolog.sh helper script into the sandbox for
on-demand evolog creation without the flag.

* fix: restore compare target when switching away from jj-evolog

When leaving Evolution diff mode, the evolog commit ID was left in
selectedBase and leaked into the next diff request. For jj-line this
caused jjLineBaseRevset() to treat the commit ID as a bookmark name,
producing a "didn't resolve to any revisions" error.

Now explicitly passes the restored default branch as baseOverride to
fetchDiffSwitch when leaving evolog, avoiding the React state batching
race that made the previous setSelectedBase-only approach insufficient.

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-05-11 21:07:15 -07:00
Michael Ramos c5b8535173 chore: bump version to 0.19.14
For provenance purposes, this commit was AI assisted.
2026-05-11 12:44:14 -07:00
Michael Ramos 071083e97d chore: bump version to 0.19.13
For provenance purposes, this commit was AI assisted.
2026-05-11 11:23:51 -07:00
Michael Ramos d0bb3badda chore: bump version to 0.19.12
For provenance purposes, this commit was AI assisted.
2026-05-11 09:38:27 -07:00
Michael Ramos 1eb561551c feat: standalone skills package + HTML render-annotate mode (#687)
Add --render-html flag to plannotator annotate that renders HTML files
as-is in an iframe instead of converting to markdown. Includes annotation
support via postMessage bridge, sharing via paste service, and theme
inheritance from Plannotator's 30+ themes.

New skill: plannotator-visual-explainer — wraps nicobailon/visual-explainer
with Plannotator theme tokens, extended patterns (timelines, SVG diagrams,
code blocks, risk tables, Pierre diffs via CDN), and plan/PR-specific guidance.

All three servers (Bun, Pi, OpenCode) support the new flag.
2026-05-11 10:30:49 -04:00
Michael Ramos 347663a4de feat(pfm): code line range references, hover preview, sketch Graphviz (#692)
Code file line range references with hover preview + Graphviz improvements.

Line ranges: `file.ts:42` and `file.ts:10-20` are fully supported with
syntax-highlighted hover preview popover (150ms delay, GitHub-style
persistence). New parseCodePath() utility, server-side line suffix
stripping on both Bun and Pi servers, ambiguous picker preserves line
suffix. useCodeFilePopout moved to hooks/pfm/.

Graphviz: responsive container height from SVG aspect ratio, white
background polygon removed, default colors (black, lightgrey) replaced
with theme tokens via SVG post-processing. User-specified colors
preserved.
2026-05-11 10:13:47 -04:00
Michael Ramos 579127e2c9 feat(ui): add Hooks visibility tab to Settings dialog (#695)
Add Hooks tab to plan review Settings dialog for visibility into the
improve-context system. PFM Reminder toggle card with config persistence,
Improvement Hook status card with collapsible content preview. New
GET /api/hooks/status endpoint and pfmReminder in POST /api/config
on both Bun and Pi servers. Dev mock API wired up.
2026-05-11 08:26:58 -04:00
Graeme Folk b5cd3d5120 fix(review): resolve jj default target from trunk (#686)
Resolve the default JJ compare target from trunk() so review UI and diff behavior use the same concrete bookmark when JJ can identify one.
2026-05-08 19:10:58 -07:00
Michael Ramos 36948e8572 chore: bump version to 0.19.11
For provenance purposes, this commit was AI assisted.
2026-05-07 23:24:00 -04:00
Graeme Folk 69ef11bdfb feat(review): add jj review workflows (#675)
* feat(review): add jj support for local diffs

* feat(review): add jj review workflows

* fix(review): tighten jj diff defaults

* test(review): add jj manual sandbox

* fix(review): share jj agent diff prompts

* fix(review): quote jj agent revsets

* feat(review): share jj vcs handling with pi

* fix(review): tighten jj bookmark and pi pr handling

* fix(review): tighten jj defaults and detection

* fix(review): harden jj diff and vcs detection

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-05-07 19:57:33 -07:00
Michael Ramos 71492ec880 chore: bump version to 0.19.10
For provenance purposes, this commit was AI assisted.
2026-05-06 16:13:46 -07:00
Michael Ramos 49c55e6e25 Revert "Expose bypass clear reminder permission mode (#668)"
This reverts commit 3b88415aeb.
2026-05-06 16:10:31 -07:00
Michael Ramos cc57710df2 chore: bump version to 0.19.9
For provenance purposes, this commit was AI assisted.
2026-05-06 15:57:39 -07:00
Nehr 3b88415aeb Expose bypass clear reminder permission mode (#668)
* Preserve truthful approval semantics for Claude plan bypass

Thread a clear-context reminder flag through approval decisions, expose a Claude Code-only approval entry that requests bypass mode, and keep the hook response honest by emitting a reminder instead of claiming context was cleared.

Constraint: Claude Code PermissionRequest hooks have no documented clearContext response field and bypassPermissions is only a request when the mode is available.

Rejected: adding a permission-mode enum or undocumented clearContext field | those would misrepresent hook capabilities and broaden the contract.

Confidence: high

Scope-risk: moderate

Directive: Do not claim Plannotator clears context until Claude Code documents a hook field for that behavior; keep reminder copy truthful.

Tested: bun test packages/server apps/hook; bun test packages/editor/wideMode.test.ts packages/ui/hooks/useAgentSettings.test.ts; bun test; bun run build:review; bun run build:hook; bun run typecheck; git diff --check --cached.

Not-tested: Browser warning-dialog replay and interactive Claude Code smoke test.

Co-authored-by: OmX <omx@oh-my-codex.dev>

* Keep approval payloads truthful across Claude Code and Pi

Constraint: Claude Code hooks cannot clear context directly; the new action remains a truthful reminder plus bypass-mode approval.
Rejected: Sending OpenCode agent-switch state for Claude Code | it leaked build (?) UI state and misleading payload fields.
Confidence: high
Scope-risk: narrow
Directive: Keep OpenCode agent switching gated to opencode-origin approval payloads.
Tested: bun run typecheck; bun test; bun run build:review; bun run build:hook
Not-tested: Manual browser click-through of the Claude Code dropdown.

* Expose the clear-context reminder permission default

Constraint: Claude Code hooks can only emit a systemMessage nudge, not clear context directly.

Rejected: Server protocol changes | existing permissionMode plus clearContextNudge wire fields already support the behavior.

Confidence: high

Scope-risk: narrow

Directive: Keep bypassPermissionsClearReminder as a UI/storage-only synthetic mode that decomposes before /api/approve.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd apps/review build && bun run build:hook; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Root bun run typecheck could not run because tsc was not on PATH for the root script.

* Reject invalid persisted permission modes

Constraint: Stored browser values can be stale, corrupt, or from a future Plannotator build.

Rejected: Trusting the storage read with a type assertion | invalid values could flow into UI state and approval request construction.

Confidence: high

Scope-risk: narrow

Directive: Keep PermissionMode storage reads validated against PERMISSION_MODE_OPTIONS when adding or renaming modes.

Tested: bun test packages/editor/approvalBody.test.ts; bun run --cwd packages/ui typecheck; git diff --check

Not-tested: Full repo typecheck/build, outside this review-fix scope.

* Ensure approvals use the live permission setting

Settings persisted permission mode changes, but App kept the original mode in React state and used that stale value when building approval payloads. Push the Settings change back into App so the selected clear-reminder mode reaches the hook decision.

Constraint: Permission mode storage is cookie-backed while approval payload construction reads App state.\nRejected: Read permission cookies during approval | would couple approval construction to browser storage and duplicate Settings state.\nConfidence: high\nScope-risk: narrow\nDirective: Keep permission-mode writes synchronized with approval state when adding or changing modes.\nTested: bun test packages/editor/approvalBody.test.ts packages/ui/components/ApproveDropdown.test.tsx; bun x tsc --noEmit -p packages/ui/tsconfig.json; bun run build:hook; direct Playwright hook smoke verified bypassPermissionsClearReminder UI and hook payload.\nNot-tested: Live interactive Claude CLI session; direct hook/server simulation covered the wire output.

---------

Co-authored-by: OmX <omx@oh-my-codex.dev>
2026-05-05 12:27:16 -07:00
Michael Ramos ff2759b553 chore: bump version to 0.19.8
For provenance purposes, this commit was AI assisted.
2026-05-05 00:26:16 -07:00
Michael Ramos 84a0b434f9 fix(ui): smart resolution + existence-validation for code-file paths (#654)
* fix(ui): smart resolution + existence-validation for code-file paths

The bare-prose / backtick path detector linkifies anything that looks
like a code path. Two failure modes regularly produce dead links: prose
abbreviations like `editor/App.tsx` (real file is
`packages/editor/App.tsx`) and references to files the plan proposes
but hasn't created yet. Both 404 on click with no UX cue.

Resolves abbreviated paths via a case-insensitive suffix-match against
a cached project walk (`resolveCodeFile` in `packages/shared/resolve-file.ts`),
mirroring what `resolveMarkdownFile` already does for markdown. The walk
is pre-warmed when the plan/annotate server boots and on every
`/api/doc` request, with a 30s TTL so newly-created files can resolve
mid-review. Storing the walk as a Promise makes the cache race-safe —
concurrent callers piggyback rather than starting a second walk.

A new `POST /api/doc/exists` endpoint takes a batch of candidate paths
and reports `found` / `ambiguous` / `missing` / `unavailable` per path.
On the frontend, `useValidatedCodePaths` extracts candidates from the
markdown on load and POSTs once. The renderer reads the result via
`CodePathValidationContext`: `found` opens directly with the resolved
absolute path, `ambiguous` opens a `CodeFilePicker` popover listing all
matches (common in monorepos where `App.tsx` exists in several
packages), `missing` demotes the link to plain code, and `unavailable`
falls back to the optimistic linkification we have today. While
validation is in flight, every detected path renders as a link, so
first paint is unchanged.

The detection itself gets a shape filter (`isPlausibleCodeFilePath`)
that hard-rejects shell brace expansion (`{a,b}`), glob wildcards, and
whitespace, while explicitly allowing `[` / `]` so Next.js dynamic
routes (`app/[slug]/page.tsx`) still resolve. The bare-prose regex moves
out of `InlineMarkdown.tsx` into `code-file.ts` so the renderer and the
new server-side extractor use the same source of truth, and the
extractor strips fenced code blocks, HTML comments, and URL ranges
before scanning so it only emits candidates the renderer would actually
paint.

Pi extension mirrors the Bun changes (handler upgrade, pre-warm,
`/api/doc/exists` route). When the popout's `/api/doc` request 404s the
dialog now surfaces "File not found in repo: <path>" instead of
silently swallowing the error.

Tests: `code-file.test.ts` extended with shape-filter and Next.js-route
cases; new `extract-code-paths.test.ts` covers extraction, dedup,
fenced/HTML/URL exclusion, and the URL-with-parens regression; new
`resolve-file.test.ts` covers the suffix-match strategy, leading `./`
handling, ambiguous results, and ignored-dir behavior.

* fix(ui): thread doc-base through code-path validator

Out-of-tree linked docs (and annotate-mode files outside cwd) reference
files relative to themselves. The validator was resolving against cwd
only, so those paths got marked missing and the renderer demoted them
to plain text — even though clicks still resolved correctly via base.

Also tightens the suffix-match's leading-segment strip so `../foo.ts`
no longer silently misresolves to an unrelated `foo.ts` in cwd.

Cleanup: delete unused extract-code-paths import in reference-handlers,
add the export entry to packages/shared so consumers don't rely on
Bun's lenient subpath resolution. Add TODO(security) comments at both
handleDocExists sites flagging that absolute paths bypass project-root
containment.

223 tests pass (3 new resolver cases for baseDir + ../ regression).

* refactor(editor): dedupe activeDocBaseDir; expand security TODO

Self-review fallout:

1. The doc-base expression `linkedDocHook.filepath ? dirname(...) :
   imageBaseDir` lived in two places (click-time URL builder and Viewer
   prop). If they drift, validator and click resolve against different
   bases and we silently re-introduce the demote-correct-link bug.
   Extract to a single useMemo.

2. The handleDocExists security TODO mentioned absolute paths in
   `paths[]` but I just added `base` acceptance, which has the same
   shape of leak (hostile sender supplies base=/secret/dir + relative
   path). Both vectors flagged in one TODO, mirrored Bun + Pi.

223 tests pass; both builds clean.

* fix(ui): code-file popout shows real error; misc consistency

Review fallout:

- `CodeFilePopout` hardcoded "File not found in repo" regardless of
  cause. The hook already captures the server's error string, so an
  ambiguous-path 400 (which can happen if a user clicks an optimistic
  link before validation completes) was surfacing as a misleading
  not-found message. Render the actual `error` and only show the
  planned/future-file caveat when the error matches "file not found".
- `InlineMarkdown` emitted demoted bare-prose paths as raw strings
  while every other plain-text branch in `emitPlainTextWithBareUrls`
  routes through `transformPlainText`. Cosmetic-only today since
  paths rarely contain transformable content, but the divergence
  invites copy-paste rot. Routed through the same helper.
- CLAUDE.md missed the new POST /api/doc/exists endpoint in both
  Plan Server and Annotate Server tables. Added.

223 tests pass; both builds clean.

* fix(ui): demote paths the extractor excluded from validation

When the validator is ready but a candidate path has no entry in the
validated map, the extractor intentionally excluded it — e.g. inside
an HTML comment or fenced code block. The renderer was optimistically
linking these because gateCodePath returned 'link' for missing entries.

Found during manual testing: `<!-- packages/editor/App.tsx -->` inside
a paragraph (parser doesn't recognize HTML comments as block-level)
was rendered as a clickable link. The extractor correctly stripped the
comment, but the renderer's optimistic fallback overrode that.

Also adds manual test harness: tests/manual/path-detection/ with
sandbox setup + three launcher scripts (plan mode, annotate in-tree,
annotate out-of-tree) covering ~30 test cases.

223 tests pass; both builds clean.

* fix(ui): skip HTML comments in InlineMarkdown scanner

The parser doesn't recognize <!-- --> as block-level HTML, so comments
inside paragraphs fall through to InlineMarkdown. The scanner then
finds paths inside the comment text and linkifies them.

The previous gateCodePath fix (demote when not in validated map) didn't
help here because the same path appeared elsewhere in the document —
the map had an entry from the non-comment occurrence.

Fix: match <!-- ... --> at the top of the scanner loop and skip the
entire comment. HTML comments should be invisible per CommonMark spec.

* fix: handle unavailable variant in markdown resolve narrowing

The shared ResolveResult type gained an `unavailable` variant for code
files. The markdown resolver never returns it, but TS can't narrow
past it without an explicit guard. Both Bun and Pi handlers now guard
`not_found || unavailable` before accessing `result.path`.
2026-05-04 14:21:16 -07:00
Michael Ramos 6fc60a6a84 chore: bump version to 0.19.7
For provenance purposes, this commit was AI assisted.
2026-05-02 14:01:25 -07:00
Michael Ramos 6324a0c859 chore: bump version to 0.19.6
Co-authored-by: Eric Clemmons <15182+ericclemmons@users.noreply.github.com>

For provenance purposes, this commit was AI assisted.
2026-05-01 18:38:10 -07:00
Michael Ramos 5aaac6bc88 chore: bump version to 0.19.5
For provenance purposes, this commit was AI assisted.
2026-05-01 00:14:59 -07:00
Michael Ramos 9b7c39d2a4 fix(review): move hide-whitespace to server-side git diff -w (#635 follow-up) (#638)
The client-side approach from PR #635 normalized file contents before
diffing, which destroyed all indentation. Move whitespace handling to
the server by threading a `-w` flag through the git diff pipeline.

- Add `GitDiffOptions` to review-core.ts, inject `-w` in all 7 diff
  type paths + untracked file diffs
- Thread options through git.ts → vcs.ts → review.ts / Pi server
- Read `hideWhitespace` from ~/.plannotator/config.json on startup so
  the initial diff already respects the persisted preference
- Accept `hideWhitespace` in `/api/diff/switch`, echo in responses
- Client toggles trigger a lightweight server refetch that preserves
  the active file (no panel reset)
- Handle edge case where current file disappears when `-w` removes
  whitespace-only diffs
- Remove broken client-side parseDiffFromFile/normalize hack
- Update API docs in AGENTS.md

Closes the indentation bug reported by @zeroZshadow on PR #631.

For provenance purposes, this commit was AI assisted.
2026-04-30 17:23:55 -07:00
Michael Ramos 657cccaee0 fix(review): support non-ASCII and whitespace file paths in code review (#637)
Pass `-c core.quotePath=false` to all git invocations so paths with
non-ASCII characters (Korean, Chinese, accented, etc.) and whitespace
are output as raw UTF-8 instead of octal escapes. Fixes the 0/0 files
issue when repos contain such paths.

Closes #628

For provenance purposes, this commit was AI assisted.
2026-04-30 13:01:27 -07:00
Michael Ramos 3636e9ed76 chore: bump version to 0.19.4
For provenance purposes, this commit was AI assisted.
2026-04-30 11:09:41 -07:00