Commit Graph

12 Commits

Author SHA1 Message Date
Michael Ramos 27791a6fba Mobile Phase 2B: Plan shell and navigation (#1303)
* feat(editor): add compact plan navigator

* feat(editor): simplify compact plan chrome

* fix(editor): close compact navigator after file selection

* feat(editor): add compact plan review surfaces

* fix(editor): hold navigator through cold file loads

* fix(editor): preserve desktop diff activation
2026-08-13 09:38:14 -07:00
Michael Ramos e181b824cc Mobile-safe plan and code comment composition (#1297)
* feat: harden mobile comment composition

* fix(ui): keep mobile app inside Safari viewport

* docs: record physical mobile triage

* fix(ui): extend plan canvas behind Safari controls

* fix(ui): let mobile plans drive Safari chrome

* fix(ui): release Safari top edge on mobile plans

* docs: triage mobile feedback and close phase 1b

* fix(ui): harden compact touch behavior
2026-08-13 08:58:55 -07:00
Michael Ramos d53cbfb373 fix(annotate): enforce archive read-only surfaces (#1171)
* fix(annotate): enforce archive read-only surfaces

* fix(archive): close remaining read-only leaks
2026-07-31 17:23:44 -07:00
Raúl 9a450a69e7 feat(annotate): preserve notes on structured approval (#1092)
* feat(annotate): add strict atomic result output

* feat(annotate): exit 2 for strict-gate usage and publication errors

Adopt the grep convention for the strict annotate gate's exit codes:
0 = approved, 1 = negative human outcome (annotated/dismissed under
--require-approval), 2 = the gate itself was misconfigured or could not
start/deliver a decision. Previously all usage/startup/validation
failures shared exit 1 with "reviewer did not approve", so callers could
not tell a denied review from a broken gate.

- parseStrictAnnotateOptions failures (bad flag combos, strict flags
  outside annotate --gate --json) now exit 2
- --result-file preflight failures (missing parent, pre-existing or
  dangling-symlink destination) now exit 2
- post-decision publication failures (destination raced into existence,
  hard links unavailable, stdout write failure) now exit 2: they deliver
  no decision record at all, so the code's own fail-closed handling
  presents them as environment errors, never as a reviewer outcome --
  and never approval, since only 0 means approved
- decision outcomes keep 0/1 exactly as before; signal deaths keep 128+n
- document the contract in AGENTS.md and the annotate-gates guide

Claude-Session: https://claude.ai/code/session_01YXkgsNucxDwAL4GdR4XYRk

* feat(annotate): preserve notes on structured approval

* test(pi): use exact annotate outcome import

* fix(annotate): exit 2 for strict-gate startup failures

The six startup-failure sites in the annotate path (missing path, unreachable
URL, empty folder, ambiguous name, missing/unsupported file, oversized file)
run after flag parsing and exited 1. Under --require-approval / --result-file,
1 is the "reviewer requested changes" signal, so a typo'd path made automation
misclassify a configuration error as a legitimate rejection.

Route those sites through exitAnnotateStartupFailure(), which picks its code
from the already-parsed strict options via the new pure helper
annotateStartupFailureExitCode(). Non-strict invocations still exit 1 with
byte-identical stderr; strict invocations exit STRICT_GATE_ERROR_EXIT_CODE (2).

Claude-Session: https://claude.ai/code/session_01H5KQWqXqjrPxyxUNso1QHS

* fix(annotate): emit the strict decision on stdout before publishing it

writeResultFile ran before the decision JSON reached stdout. On a filesystem
without hard links (exFAT, FAT32, most SMB/NFS, some container bind mounts)
publication fails deterministically, the catch exited 2 with nothing written
anywhere — and the reviewer's autosaved draft had already been deleted by the
feedback flow, so their completed decision was lost.

Emit the stdout record first, then publish the result file. Exit semantics are
unchanged: a publication failure still exits 2, but the decision has reached
stdout by then. Only a stdout write failure now leaves no record at all.

Correct the docs and comments that claimed exit 2 delivers no decision record:
it means the result *file* was not published. Also document the two publication
caveats: the 0600 mode is a no-op on Windows, and the atomic link/rename is not
followed by a parent-directory fsync, so publication is atomic but not
crash-durable.

Claude-Session: https://claude.ai/code/session_01H5KQWqXqjrPxyxUNso1QHS

* fix(annotate): parse linked docs with the render-side frontmatter rule on export

buildCompleteAnnotateFeedback re-parsed each linked document with
parseMarkdownToBlocks(entry.markdown) — no options, so frontmatter
stripping defaulted on. The render side parses with
{ frontmatter: shouldStripFrontmatter(path) }.

For plain-text linked docs (.yaml/.json/.toml/…) a leading `---` is real
content, not frontmatter: a multi-document YAML opens with it. Stripping
it on the export side shifted every block id, so ordinary Send Feedback
and deny emitted wrong `(line N)` labels — or dropped them entirely when
the annotation's block no longer existed.

Pass the same shouldStripFrontmatter(filepath) option at the export call
site so both sides agree.

Claude-Session: https://claude.ai/code/session_01H5KQWqXqjrPxyxUNso1QHS

* fix(annotate): carry the message scope through approve-with-notes

/api/feedback forwards selectedMessageId and feedbackScope; /api/approve
dropped them. Pi resolves the anchor message from those fields, so notes
delivered on the approve path anchored to the last message instead of the
one the reviewer picked in a multi-message annotate-last session — while
Send Feedback in the same session anchored correctly.

Forward both fields on the approve path in the Bun and Pi servers, and
have the client build the approval body with the same scope resolution
Send Feedback uses (extracted as getFeedbackMessageScope so the two can
no longer drift).

Claude-Session: https://claude.ai/code/session_01H5KQWqXqjrPxyxUNso1QHS

* docs(annotate): tell agents an approval may carry notes

The skill and slash-command files still described `"decision": "approved"`
as "acknowledge and stop", with no mention of the feedback field the gate
can now attach — so an agent reading them would silently drop the
reviewer's approval notes.

Update the Claude core/claude skills, the Copilot commands, the Gemini
annotate command, and the annotate command reference so the approved
branch names the optional feedback field and says what to do with it:
carry it into subsequent work, do not treat it as a change request.

Claude-Session: https://claude.ai/code/session_01H5KQWqXqjrPxyxUNso1QHS

* docs(annotate): document the real approvedWithNotes default

The default annotate.approvedWithNotes template is
`{{contextBlock}}{{feedback}}`, not `{{context}}` on its own line, and
{{contextBlock}} was missing from the variable table entirely.

Show the actual default, add {{contextBlock}} to the variable table, and
explain why the default prefers it: it collapses to nothing for message
annotations instead of leaving a stray blank line.

Claude-Session: https://claude.ai/code/session_01H5KQWqXqjrPxyxUNso1QHS

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-07-26 21:09:28 -07:00
Leonardo Reis 73cd4b121d feat(annotate): add sidebar shortcuts (#986)
* feat(annotate): add sidebar shortcuts

* fix(shortcuts): double-tap requires solo presses

The double-tap engine counted ANY two keyups of the tracked key within
the window, so the new Shift Shift agent-terminal toggle fired during
ordinary Shift usage: typing two capitalized words, extending a
selection with two Shift+Clicks, or pressing this PR's own Mod+Shift+B
twice. A tap now only counts when the key went down and came up alone —
any other keydown, a pointer interaction mid-press, or another modifier
held at release breaks the press and resets the sequence. Also honors
the binding's preventDefault flag in the double-tap path (it was a
silent no-op).

---------

Co-authored-by: Michael Ramos <mdramos8@gmail.com>
2026-07-06 19:13:12 -07:00
Michael Ramos f9ff55bfe0 feat(annotate): show annotation count badge in plan/annotate header (#979)
The plan-review and annotate apps share AppHeader, whose annotations
toggle had no count badge — unlike the code-review app's equivalent
button. Add a numeric badge (capped at 99+) driven by the existing
feedbackAnnotationCount, so both surfaces now surface how much feedback
is pending. Closes the parity gap with the code-review header.
2026-06-29 15:12:43 -07:00
Michael Ramos 9ed3ba8937 feat(editor): markdown edit mode — direct document editing with diff-to-agent feedback
Adds direct markdown editing, source-backed annotate saves, folder edit buffers, and review-hardening fixes.
2026-06-16 16:35:51 -07:00
Michael Ramos c23df4db43 UI 2.0 visual refresh + HTML-render annotate (strictly UI, off main) (#863)
Extracts the UI 2.0 visual refresh and the HTML-render annotate feature onto main, standalone (no daemon). Faithful copy of feat's UI/HTML logic with the standalone transport kept.
2026-06-08 17:03:41 -07:00
Michael Ramos dbe2d6e4cb Replace update banner with passive dot indicator in Options menu (#793)
* Replace persistent update banner with passive dot indicator in Options menu (#790)

The floating update banner that appeared every session is removed. Update
availability is now surfaced as a small dot on the Options button that
auto-dismisses (cookie-persisted per version) when the menu is opened.
The version section inside the menu shows install command and release
notes when an update exists.

* fix: restore ActionMenuSectionLabel import in both header menus

* Add TextShimmer to update notice and simplify menu version section

- Add reusable TextShimmer component (motion-primitives adaptation)
- Add reusable BorderTrail component for future use
- Shimmer "New update available!" text in the Options menu
- Simplify button to plain text link in emerald
- Remove Project repo link, make "Plannotator" header link to repo
2026-05-25 12:09:42 -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 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 f4493fc6ff Optimize plan editor rendering (#696)
- Replace blocks/frontmatter useState + useEffect with useMemo (eliminates mount cascade)
- Migrate toast notifications from React state to Sonner (App no longer re-renders for toasts)
- Extract AppHeader component with React.memo (header no longer re-renders on unrelated state changes)
- Fix color transition flash on initial load (suppress global * transition until mount settles)
- Add Tailwind @source path for new editor components directory
2026-05-11 08:55:18 -04:00