Repository navigation
QuillPost 1.5.0: rename, command set and QAT, AI tab, embedded QuillPen, every mail format, phone layout - #4
Merged
Merged
Conversation
Implements QuillPost's side of the suite embed protocol: - compose: a QuillPen button (and openInQuillPen() for the command registry) opens the body in an iframe that fills the compose body; postMessage protocol with source and origin checks, 8 s ready timeout with fallback to the built-in editor, Send and draft saves request the current content first, Cancel keeps the old body, incoming HTML is sanitised before it enters the page - Settings > Compose: Edit messages in QuillPen (Off/Ask/Always) when QuillPen is found; QuillPen folder (desktop) or web address (web); hidden on iOS - Android: <queries> for the QuillPen package and provider, detection, https://quillpen.embed/<path> answered from QuillPen's ContentProvider with MIME types, availability exposed to the page - desktop: finds resources/embed in the standard install locations or a chosen folder (native picker) and serves it at /quillpen-embed/<path> with path-traversal checks - tests: unit tests for path resolution and install locations; a fake QuillPen page and a Playwright test of desktop, web, Android and iOS Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Installs the suite scroll cues (thin scrollbar that widens when used, edge shadows, a More chip) on every menu, autocomplete list, dialog, settings page, folder and side pane, provider grid, rule preview and My Day; long content lists (messages, contacts, tasks, reading pane, editors, calendar grid) get the thin scrollbar without the chip. Bars that scroll sideways on narrow screens (ribbon, compose tabs and formatting bars, settings tabs) get edge shadows. Colours follow the app's light and dark tokens. Fixes in the shared module (applied to the suite copy too): the chip of a container inside a modal dialog now lives in that dialog, since anything outside the top layer is drawn under it and inert; only containers that can really scroll get a chip; the chip is placed in the part of the container that is not clipped by a scrolled ancestor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
- Android: adaptive-icon foreground converted path for path from the suite's icon-foreground.svg, background #0D7C86, splash icon is the full gradient tile inside the splash mask - iOS: 1024 px app icon (full bleed, no alpha) and launch logo - desktop: .png/.ico/.icns installer icons wired into the Compose native distributions; window and tray icon - web: SVG favicon, Apple touch icon, the start-up splash mark - branding/QuillPost holds the suite sources; scripts/gen-icons.mjs regenerates every raster from them Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
…ands The Mail ribbon gets an AI tab (also reachable from the reading pane's AI button, the compose window's AI tab and an AI assistant pane). Ported from the sister apps' AI modules to plain JavaScript under web/ai/: - provider registry: on-device Transformers.js model in a Web Worker, the browser's built-in model, free tiers, Ollama / LM Studio, paid keys and any OpenAI-compatible service; wizard with grouped providers, key test and live model list; Active AI, Providers & models, AI settings, usage, AI & Privacy, Stop, Delete downloaded models, Prompt library - client: OpenAI-compatible, Anthropic and Gemini request builders, SSE streaming with abort, parameter retry, usage; providers without CORS go through a new backend relay (/api/ai/proxy) that only forwards to the provider table's hosts and addresses the account registered - email commands: summarize message/thread, draft reply (tone, length, accept/decline/details/thank), rewrite, translate, proofread, subject line, template, action items -> To Do, events -> Calendar, contacts -> People, classify, explain jargon, phishing check, follow-up, ask about this mailbox (headers only by default), unsubscribe helper - changes are previewed and applied as one undoable step; every answer shows what was sent - keys: Android Keystore-encrypted store via a new QuillboxAndroid bridge, the desktop backend's private data folder (owner-only permissions), or IndexedDB on the web; never in settings or exports Tests: node --test web/src/test/js (wired into `check` as jsTest) and AiRoutesTest for the relay allow-list and desktop key file. Docs in docs/AI.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
- Insert/Replace in a draft now selects inside the user's own text, checks that the quoted original and the signature are unchanged afterwards, and places the text directly if the browser merged it into them (Chrome did, dropping the quote's rule) - The relay never connects to link-local addresses, and reaches loopback or private addresses only for browsers on loopback or a private network (QUILLBOX_AI_RELAY_PRIVATE=on/off overrides), so an internet-facing Quillbox cannot be used to reach its own network Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Every action is now a registered command shared by the ribbon, a Quick Access Toolbar, context menus, command search (Alt+Q) and customisable keyboard shortcuts (with Gmail- and Mutt/Pine-style schemes). - commands.js: registry, key names and keymaps, QAT model (standard Mail choices, Add All Choices with Save and Print first, sanitising) - qat.js / commands.css: QAT above/below the ribbon or at the bottom, drop-down checklist, More Commands chooser, import/export, touch mode, command search, keyboard customisation, command reference, File backstage, Send / Receive, Folder and Tools ribbon tabs, compose Review and Draw tabs - mailcommands.js: the desktop client's Mail commands (File, Home, Send / Receive, Folder, View, Help, Message, Insert, Options, Format Text, Review, Draw), Undo/Redo of mail actions - mailextra.js / mailtools.js: commands from Eudora, Pine/mutt, Pegasus, Lotus Notes, Thunderbird, Outlook Express, Gmail, Apple Mail, Hey/Superhuman/Spark, Claris Emailer and Opera M2, plus new commands (time slots, thread digest, waiting for reply, one-click unsubscribe, header inspector, quote integrity, triage…) - Backend /api/x/* endpoints: redirect/bounce with Resent-* headers, IMAP keywords and flags, compact, mark read by date, archive by year/month, folder stats and copy, large messages, strip attachments, subject edit, mailing lists, RFC 8058 unsubscribe, header inspector, awaiting replies, outbox flush, muted/routed conversations, state store - Message summaries carry IMAP keywords - Tests: Node unit tests (web/src/test/js) and CommandFeaturesTest.kt - docs/COMMANDS.md and a README section Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
IMAP deletions already expunge explicitly, so closing a folder no longer expunges as well: a Pine/mutt "mark for deletion" now survives until Compact Folder. POP3 still deletes on close. Messages rewritten by Delete Attachments or Edit Message no longer raise a new-mail notice. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
The suite regenerated icon-foreground.svg so that the quill tip stays inside Android's 66dp safe circle (it was clipped in round launcher icons); the vector drawable follows it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Takes the suite's newer scrollcue.js/.css (no hover widening, chips stay inside narrow containers, no stacked chips for nested scrollers, keyboard-aware placement, destroy()); it already contains the fixes made here (chip inside the modal dialog's top layer, real scrollers only). Dark mode sets the chip text colour through --sc-on-accent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
A phone layout audit (web/src/test/e2e/layout.mjs) opens every dialog, menu, drawer and overlay at 412x915, 360x640 and 915x412 with system-bar insets and the keyboard, and checks the safe area, covered or overlapping controls and sideways scrolling. Defects it found, fixed: - collapsing the folder pane (wider than 700 px: landscape phones, tablets, desktop) left the message list in a zero-width grid column, so the mail view went blank - the immersive reader's toolbar did not wrap on phones: the dialog scrolled sideways and its Close button was off screen - toasts covered the New mail button on phones and the Send button of a message docked in the reading pane - with the keyboard up on short screens (landscape, 360x640) the message window squeezed the editor to nothing and clipped Send; it now fills the screen and scrolls, keeping the editor usable - in a browser or home-screen web app (viewport-fit=cover) nothing respected env(safe-area-inset-*): the title bar, bottom navigation, full-screen dialogs, menus, drawers, toasts and the New mail button sat under the status bar, home indicator or cut-outs safearea.css/js add --sa-* inset variables (env() by default), pad the page and place dialogs, drawers, toasts and floating buttons inside the safe area, keep pop-up menus inside it, and measure keyboard overlap from visualViewport where the browser does not resize the page; the viewport asks for interactive-widget=resizes-content. The Android and iOS shells already pad the WebView natively (insets stay 0 there). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
AI settings gain "Use several AIs": tick two to six configured providers (each with a model), pick a master/clerk, the rounds of discussion and whether to show the discussion. In master mode every AI answers and the master writes the best answer from the shuffled, anonymized responses. In consensus mode a clerk drafts a minute, the AIs unite, stand aside or block, and blocks send the minute back for revision; without unity the clerk's last minute is returned and the objections are shown. The orchestration lives in ai/ensemble.js and depends only on an injected call(), so it is tested with mock providers. The client's chat() uses it for requests that name no provider; each member call keeps its own route, including the relay fallback. Progress reaches the AI pane and previews, "How the AIs answered" shows each answer, round and outcome, and commands apply only the final answer. The AI tab gets Several AIs, Choose AIs and Show AI Discussion (also in QB_AI_COMMANDS); the cost note and every privacy notice list each service that receives the text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Serve the desktop embed on a separate origin (localhost instead of 127.0.0.1) so the embedded editor cannot read QuillPost's storage, and register Edit in QuillPen as a command for the Quick Access Toolbar. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Register the AI tab's commands in the command registry so they can go on the Quick Access Toolbar, custom tabs, shortcuts and command search. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Every name, identifier, package, path, help page and metadata entry now says QuillPost. App IDs follow the suite pattern io.github.socrtwo.*. Existing installs keep working: ~/.quillbox is moved to ~/.quillpost on first start, and QUILLBOX_* settings and quillbox.* properties are still read when the new names are not set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
… office files Adds the fileformats package: a compound-file reader (MS-CFB), Outlook .msg/.oft items (MS-OXMSG: messages, contacts, appointments, tasks, embedded messages, named properties), winmail.dat (MS-OXTNEF), compressed RTF (MS-OXRTFCP), HTML de-encapsulation (MS-OXRTFEX) and an RTF-to-HTML renderer, a forgiving MIME reader (RFC 2047/2231, 8-bit headers, UTF-7, broken boundaries, format=flowed, text/enriched, uuencode, yEnc, BinHex, AppleSingle/AppleDouble, S/MIME and PGP), MHTML, .emlx and .nws, vCard 2.1 quirks, Windows .contact, vCalendar 1.0, and content detection of word-processor, spreadsheet and presentation files. MessageFormats.detect/parse/toRfc822 is the API for the import pipeline. Tests build every fixture from the specifications. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Content-based detection of mailboxes, single messages and office documents, readers for mbox (all dialects, Gmail Takeout), Maildir, MH, Apple Mail, Eudora, Outlook Express (.dbx, OE4), Outlook .pst/.ost/.pab (clean-room from MS-PST, with compressed RTF and encapsulated HTML), Pegasus Mail and The Bat!, an import pipeline into IMAP folders or a new read-only Local Archives store, and the File > Open / Import Mailbox UI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
New "Open file" feature: mail.openFile (File > Open & Export, or drop a file on the window) sends the file to /api/file/open, which recognises it by content and returns a message, contacts, events or a document description. Messages open in a reader window with Reply, Reply all, Forward, Save to folder, Save as .eml, Headers and their attachments (attached messages and documents open in turn); images load only from the file itself, remote images and tracking pixels stay blocked. Outlook templates open as a new draft. vCards and Windows contacts go to People, iCalendar and vCalendar files to the calendar. Documents, spreadsheets and presentations offer Open in QuillPen, QuillGrid or QuillStage and Send as attachment (mail.sendFileAsAttachment). sanitizeHtml takes an optional cidUrl so inline parts of opened files resolve. Sample files, JS unit tests and a Playwright check (src/test/e2e/openfile.mjs). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
…rchives, browser test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
…s, Open with, share) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
…fixes Android: "Open with QuillPost" (messages, contacts, calendars and generic binary files) and "Share to QuillPost" hand the files to the in-process backend, which the page picks up and shows; "Open in QuillPen/QuillGrid/QuillStage" starts the suite app with a content:// URI and falls back to any viewer. Desktop: file arguments and macOS open-file events are opened in the UI, a second launch hands its files to the running instance (key-protected local route), documents open with the program the system registered for them, and the installers register .eml, .emlx, .nws, .msg, .oft, .mht, .tnef, .vcf, .ics and .vcs. Readers: recipients and attachments of Outlook items use the message's code page; plain text is derived from HTML-only bodies; subtype-less content types, wrong boundary parameters, delivery reports, inline text parts and Content-Description names are handled. Opt-in ExternalSamplesTest runs the readers over a folder of real files. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
… Outlook items docs/FORMATS.md gets "Messages, contacts and calendars" (program, versions, extensions, detection signature, fidelity tier and limitations for every single-item format) and "Documents, spreadsheets and presentations" (what is recognised and handed to QuillPen, QuillGrid or QuillStage). The README describes opening files. Fixture sources and licences are recorded in web/src/test/resources/fixtures/README.md. Outlook S/MIME items (IPM.Note.SMIME*) now show the message inside their smime.p7m attachment. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
… and detection Single messages, contacts, calendars and office files are detected and read by the fileformats package; PST/OST items go through its MAPI converter (original transport headers now kept by MimeWriter); mailboxes opened from Open File, drops or the shells are routed to Import Mailbox. The duplicate Open File command, RTF code and shell hand-off are removed. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
…ones and desktops The phone layout audit failed again after the command registry, Quick Access Toolbar, AI tab, file-open window and mailbox import were merged. Root causes and fixes: - Title bar: with the Quick Access Toolbar in it, its buttons were wider than a 360 px screen, so the browser widened the layout viewport and every page, dialog, menu and the New mail button ran off the screen. The search box now gives way (with a minimum), the toolbar shrinks and scrolls, and narrow phones keep one toolbar command. - Toasts were drawn beneath an open modal dialog (Undo could not be pressed): the toast host now moves into the top modal dialog as a line at its foot. Modal dialogs are tracked in opening order, so menus, toasts and the AI busy chip go to the dialog that is really on top. - The Quick Access Toolbar at the bottom floated over the list, the New mail button and a docked reply's Send button: it is now a bar of its own under the app, and floating buttons, toasts, drawers and panes keep above it (--app-b). - AI pane: below the title bar and clear of the system bars, the keyboard and a bottom toolbar; full height and scrolling in short windows. On wide screens the mail panes share what is left so the reading pane keeps a readable width, and its toolbar wraps when narrow (container query) instead of setting the subject one letter per line. The AI busy chip is a line of its own. - Menus anchored to a control scrolled out of view are kept inside the safe area; the app rail scrolls in short windows; very short windows scroll the module instead of squeezing the list; settings rows wrap their buttons. - Help and Report a problem no longer navigate the app away (window.open with "noopener" always returns null). The layout audit now also opens every command of the registry, the Quick Access Toolbar in all positions with and without labels, its drop-down and chooser, the keyboard dialog, command search and reference, the File backstage, every ribbon and compose tab, the AI pane, setup, settings with several AIs and "How the AIs answered", Import Mailbox start/options/progress/ report, Local Archives, the open-file window and the embedded QuillPen editor, on 412x915, 360x640, 915x412 (insets and keyboard) and 1280x860 / 1500x900. It detects pages wider than the screen, controls cut off where they cannot be scrolled to and text squeezed into a sliver. New scroll containers get scroll cues. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DQ7NPUMmuJkkxN28Whzi6Q
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Merges the current QuillPost work into
main.Summary
io.github.socrtwo.quillpost). Existing setups keep working:~/.quillboxmoves to~/.quillposton first start,QUILLBOX_*settings andquillbox.*properties are still read.docs/COMMANDS.md).docs/AI.md).docs/EMBED.md.docs/FORMATS.md).web/src/test/e2e/layout.mjscovers every command on phone and desktop profiles. Scroll cues, safe areas, suite icon.Testing
node --test web/src/test/js/*.test.js— 88 pass.cd web && ./gradlew test— 175 tests, all pass except NetTest's live MX lookup (no DNS in the build sandbox; passes with network).Generated by Claude Code