thunderbird-patch-review

Simple email patch review tool for Thunderbird

git clone git://mccd.space/thunderbird-patch-review
commit 757f76f663162a6357b637073e2ace0b5bfc8e37
parent 2df389571ea748c01f4a29c01c1e8febef1ad13c
Author: Pi Agent <agent@pi.local>
Date:   Sun, 19 Jul 2026 10:38:54 +0200

README: finish the man-page-to-HTML conversion

The HTML draft stopped at <h2>Installation</h2> and left the rest of
the README as raw groff-text input. Finish the conversion: definition
lists for Configuration, Permissions, and Files; an ordered list for
Review workflow; <pre><code> for the zip command block; <a href> for
the introductory post and the mailing list; and the trailing
headings (Sourcehut integration, Caveats, See also, Contributing,
Author) as plain prose.

Diffstat:
AREADME.html | 172+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 172 insertions(+), 0 deletions(-)
diff --git a/README.html b/README.html
@@ -0,0 +1,171 @@
+<main>
+  <h1>Thunderbird Patch Review</h1>
+  <p>Review git patches from email inside Thunderbird</p>
+  <h2>Synopsis</h2>
+  <p>A Thunderbird MailExtension. Open a patch email, press Review,
+  comment on hunks, send the review as a mailing-list reply, and apply
+  the series to a local repository with git-am(1).</p>
+  <h2>Description</h2>
+  
+  <p>patch-review brings a review interface to git-by-email workflows
+  (git-send-email(1) style). When the selected messages (or thread)
+  look like a patch -- a [PATCH] subject tag or a unified diff in the
+  body -- the Review button in the main toolbar becomes active. It
+  opens a dedicated review tab that shows the whole series: cover
+  letter, per- patch commit messages, and every file and hunk rendered
+  as a colored diff. Within replaced lines, the span that actually
+  changed gets a stronger highlight, computed from the common prefix
+  and suffix of each deleted/added line pair.</p>
+  
+  <p>Clicking a diff line attaches an inline comment to it; comments
+  are saved as drafts (keyed by Message-ID) and survive restarting
+  Thunderbird. Send review turns the comments of each commented patch
+  into one plain-text reply-to-all, quoting the relevant hunks kernel-
+  style with the comments interleaved unquoted below the lines they
+  target, and sends the replies immediately; the draft comments are
+  then cleared and the review tab closes. The attached drop-down
+  offers Preview in compose instead, which leaves the reply drafts
+  open in compose windows. A reply that fails to send also stays open,
+  so nothing is lost. Apply series runs git am --3way on the raw patch
+  messages in the configured repository. On conflict git am --abort is
+  run and its output reported, leaving the repository untouched. Its
+  drop-down offers Modify and apply -- apply, then open the touched
+  files in your editor -- and Download patchset -- save the raw series
+  as one mbox file, ready for git am.</p>
+
+  <h2>Installation</h2>
+  <p>Package the extension as an .xpi and install it via the Add-ons
+  Manager gear menu (Install Add-on From File...). From the project
+  root:</p>
+  <pre><code>(cd extension && zip -qrX ../patch-review.xpi .)</code></pre>
+  <p>The subshell runs the zip(1) from inside extension/ so the archive
+  holds manifest.json at its root, not under extension/. git(1) is a
+  dependency (for Apply). For development, instead pick Tools -&gt;
+  Developer Tools -&gt; Debug Add-ons -&gt; Load Temporary Add-on...,
+  and select extension/manifest.json; it is dropped on restart.</p>
+
+  <h2>Configuration</h2>
+  <p>Open the extension's preferences:</p>
+  <dl>
+    <dt>Editor command</dt>
+    <dd><p>Run from the repository after a successful apply, with the
+    changed files as arguments. Use a non-blocking GUI-capable command
+    such as <code>code -n</code> or <code>emacsclient -n</code>; a bare
+    terminal editor has no terminal to open in. Empty means
+    <code>$EDITOR</code>.</p></dd>
+
+    <dt>Apply strategy</dt>
+    <dd><p><code>git am --3way</code> (default) or plain
+    <code>git am</code>.</p></dd>
+
+    <dt>Repository mappings</dt>
+    <dd><p>Substring matches against a patch's List-Id header or
+    sender, mapped to an absolute repository path. When no mapping
+    matches, the last path a series was applied to is used; it is
+    remembered until changed.</p></dd>
+  </dl>
+  <p>Repository paths can be chosen with the Browse button, which opens
+  Thunderbird's native directory chooser; the path field stays editable
+  either way.</p>
+
+  <h2>Permissions</h2>
+  <p>The extension requests the fewest permissions it needs; none are
+  granted to remote content.</p>
+  <dl>
+    <dt>messagesRead</dt>
+    <dd><p>Reads the selected message and its sibling patches in the
+    same folder (subject, author, body) to build the review.</p></dd>
+
+    <dt>accountsRead</dt>
+    <dd><p>Resolves the default identity of the account that owns the
+    reviewed message, for the From-address label and
+    send-as.</p></dd>
+
+    <dt>storage</dt>
+    <dd><p>Persists draft comments (keyed by Message-ID) across
+    restarts, plus the editor command, apply strategy, repo mappings,
+    and the last applied repository path.</p></dd>
+
+    <dt>compose, (compose.send)</dt>
+    <dd><p>Opens reply-to-all compose windows from Send review and
+    sends them in Send now mode. Without compose.send the review can
+    only be previewed in compose, never sent.</p></dd>
+
+    <dt>downloads</dt>
+    <dd><p>Writes the Download patchset .mbox to disk.</p></dd>
+
+    <dt>tabs</dt>
+    <dd><p>Opens the review tab and removes it after a successful
+    send.</p></dd>
+  </dl>
+  <p>The privileged Apply, Browse... , and Open editor code does not use
+  a Mozilla permission: it is a WebExtension Experiment
+  (<code>experiment_apis.patchHost</code>) shipped inside the XPI and
+  runs only when the extension is loaded.</p>
+
+  <h2>Sourcehut integration</h2>
+  <p>When the series arrives via a sourcehut mailing list (a
+  lists.sr.ht address in the List-Id or recipients), the review tab
+  shows a set status checkbox with the patchset states sourcehut
+  understands: APPROVED, NEEDS_REVISION, REJECTED, PROPOSED,
+  SUPERSEDED, APPLIED. When enabled, the first reply of the review
+  carries an X-Sourcehut-Patchset-Update header with the chosen status,
+  which sourcehut applies to the patchset. A status can also be sent
+  without any line comments -- Send review then sends a single, empty
+  reply to the cover letter (or first patch) carrying just the
+  header.</p>
+
+  <h2>Review workflow</h2>
+  <ol>
+    <li>Select any message of the series -- or the whole thread -- and
+    press Review in the main toolbar.</li>
+    <li>The tab collects the sibling patches from the same folder (same
+    series tag, version, and patch count).</li>
+    <li>Click lines, write comments; Ctrl+Enter saves. "Comment on
+    patch" attaches a general remark instead.</li>
+    <li>Send review: one reply per commented patch, sent immediately
+    (or use the drop-down to preview first).</li>
+    <li>Apply series: git am into the mapped repository, then Open
+    editor on the touched files.</li>
+  </ol>
+
+  <h2>Files</h2>
+  <dl>
+    <dt>extension/</dt>
+    <dd><p>The MailExtension (manifest v2, vanilla ES modules, no
+    build step).</p></dd>
+
+    <dt>extension/api/patchHost/</dt>
+    <dd><p>The privileged part (a WebExtension Experiment): runs
+    git-am(1) and the editor through Thunderbird's Subprocess API and
+    shows the directory chooser with nsIFilePicker. Everything outside
+    this directory runs as ordinary sandboxed WebExtension
+    code.</p></dd>
+
+    <dt>tests/</dt>
+    <dd><p><code>node tests/run.mjs</code> exercises the pure modules
+    (subject parsing, diff parsing, reply formatting) against fixtures
+    generated by git-format-patch(1), and checks the experiment's
+    manifest wiring. Regenerate fixtures with
+    <code>tests/gen-fixtures.sh</code>.</p></dd>
+  </dl>
+
+  <h2>Caveats</h2>
+  <p>Patches arriving as attachments, HTML-only mail, and reviewing
+  from a git worktree preview are not supported yet. Series collection
+  searches the folder of the opened message only.</p>
+
+  <h2>See also</h2>
+  <p>The introductory post can be found at
+  <a href="https://mccd.space/posts/26-07-18/3-patch-review-tool-for-thunderbird">https://mccd.space/posts/26-07-18/3-patch-review-tool-for-thunderbird</a>.</p>
+
+  <h2>Contributing</h2>
+  <p>Disclaimer: this plugin was vibe coded -- written by an AI agent
+  under human direction.</p>
+  <p>Contributions and bug reports go to the mailing list:
+  <a href="mailto:~marcc/thunderbird-review-plugin@lists.sr.ht">~marcc/thunderbird-review-plugin@lists.sr.ht</a>.</p>
+
+  <h2>Author</h2>
+  <p>Marc Coquand &lt;marc@coquand.email&gt;<br>
+  patch-review 0.1.0 -- July 2026</p>
+</main>
+\ No newline at end of file