Release v3.17.2 - #523
Merged
Merged
Conversation
* SMTP: stop tying the TLS toggle advice to port numbers Some relays (PostStack, for one) want implicit TLS on 587, so the old hint sent admins the wrong way and the connection died waiting for a greeting. The hint now defers to the relay's instructions, and a test send that fails on the greeting or a TLS handshake says to check the toggle. * Admin: ask where the test email should go The test went silently to the signed-in admin's address. The form now shows the recipient, prefilled with that address, and the result banner names it.
Notes: the long-disabled Notes segment becomes a real view at story and universe scope. New notes table (migration 0048) carries all four scope FKs; the UI creates universe and story notes (scene/chapter attachment reserved). Pinned/recent list, prose editor with autosave, pin/delete, and full History (preview + restore) reusing the revision machinery - 'note' was already in the revisions enum, so this adds the note branch to ownedEntityBody/restoreRevision and to both REVISABLE lists. The story view peeks universe notes under "From the universe". Cascade cleanup is wired into deleteStoryWithin and purgeUniverseWithin (so account deletion is covered through the universe purge), and notes ride the story, universe, and account exports under notebook/. Duplicate scene: a row-menu "Duplicate scene" makes a full copy (title plus "(copy)", body, status, summary, planning fields, and markers re-anchored) directly after the source, the building block for keeping a scene as a reusable template. Help docs and tests (integration + e2e) cover both. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
docs/SELF-HOSTING.md is the operator guide the README points to: a full environment-variable reference, reverse-proxy examples for Caddy, nginx, and Traefik, email and S3 storage setup, the backup and restore drill, health checks, updating, a single-replica scaling note, and troubleshooting. In-app help gains three articles - account (profile, public page, appearance, editor and page-setup defaults), security (password, email change, two-factor, passkeys, sessions, export, deletion), and a keyboard-shortcuts reference - registered in the docs index, and the account page's help button now opens the relevant one per section. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Autosave (scene, entity, note) and asset upload had no rate limit, unlike auth, search, and review. A shared write-guard helper applies two per-user budgets through the existing in-memory limiter: a generous autosave bucket (600/min, well above debounced multi-editor writing) shared across the save endpoints, and a tighter upload bucket (60/min). Over budget throws a 429; the editor's debounced save chain retries, so a brief throttle only delays a save. The limiter is per-process; the single-replica stance this assumes is now documented in docs/SELF-HOSTING.md. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
An account-level daily word goal (stored in users.preferences, account Display section) shows today's progress on the Session tab and the Insights page, with how many of the last 30 days met it. Each story can set an optional target length and a deadline (migration 0049, additive columns) in a new Goals section of story settings; the Insights Stories block shows a progress bar toward the target and a due-in / overdue line. Pure helpers daysMetGoal and daysUntil are unit-tested, with integration coverage for the preference and e2e for the journey. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
#286: toggleInlineMark treated a single * beside the selection as an italic mark even when it was the inner star of a bold **, so italicising an already-bold word stripped the bold. An italic toggle now only unwraps an isolated *; bold/italic compose to ***word*** in either order. #285: add visible Cancel buttons to the dashboard create forms and Esc-to-cancel to the two inline forms that lacked it (add-relationship, universe-plan new story). Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The whole-story view is the editor, but with no toolbar it read as read-only. Give it the shared formatting toolbar (acting on whichever stitched scene editor holds the caret) so it plainly invites editing. Add a read-only Preview beside it, rendered through the same renderMarkdown the export uses: underlines, TODO and selection marks, and the \center / \page literals are gone, with alignment, page breaks, scene-break text, and paragraph style applied. The preview toggle lives in the toolbar, not the top bar. Reachable as view=preview and via a "Preview the story" palette command. Help and shortcuts docs updated. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* feat: read-only entity card in the editor's right column (#288) Clicking an entity in the editor's "In this scene" list, or "Open full details" on a mention's hover, now replaces the right column with a read-only card (summary, description, typed relationships, details, and an Open in Plan link) instead of navigating away to the plan editor. Restores the prototype's EntityInspector. Related entries open in the same card; Back walks the stack and returns to the tabs from the first card. The card is fetched per id from a new owner-scoped GET /api/entities/[id]/card (getEntityCard in plan-data), so any related entity is reachable in the frame. The card closes when the open scene changes. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * test: route core-flow find-usages through the entity card's Open in Plan --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…#295) The "Read the whole story" / "Back to the scene editor" toggle and Focus mode lived in the top bar, where they read as navigation. They are editor-view controls, so move them to the right of the formatting toolbar, next to Preview, and out of the top bar (which keeps search, settings, help, notifications, and the account menu). The toolbar shows while a scene or the whole story is open; in the empty state focus mode is moot and the whole story stays reachable from Ctrl+K. TopBar drops the now-unused storyView and onEnterFocus props. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The v2.41.1 release PR run flaked on the help modal: a lone click on the help button can be dropped if it lands as the top bar re-renders, so the dialog never opened. Retry the open until the dialog shows (opening is idempotent). The same pattern fixes the entity-autocomplete popup, which could open unfiltered if Ctrl-Space landed before the typed text registered - re-ask until the filtered result shows. Test-only; no app change. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Prettier 3.9 on develop breaks these lines differently. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Review tab re-anchored every comment and suggested edit with its own character diff of the scene it sits in. A story whose scenes have moved on since the notes were left pays that diff once per anchor: on a 45k-character scene it is around 260ms each, and the load runs them back to back on one thread, so the page hangs before it renders. The threads and suggestions on a scene almost all share the same pair of texts, so an anchor mapper now diffs each pair once and maps every anchor through that one result, shared between listThreads and listSuggestions for the page. On a restored production story (20 scenes, 98 threads, 53 suggestions) that takes the load's 26 diffs down to 5, and the load itself from about 4.2s to 570ms. reanchorRange and reanchorPoint keep their signatures and behaviour; the offset maths moved into shared helpers so the cached and uncached paths cannot drift, and the new tests check the mapper against them exhaustively. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
* Add the components sheet and the design pass briefs Groundwork for the whole-app cohesion pass with Claude Design: a components sheet audited from the shipped CSS and components, four session briefs (landing, navigation, secondary surfaces, primitive consolidation), and a CLAUDE.md pointer so page work starts from the sheet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Reconcile the design docs with the shipped app design.md caught up with reality: the AI section describes the shipped Assistant (roles, BYO key, egress policy, account toggle and story mute), continuous-view editing, EPUB/PDF exports, the four sign-up modes, the flat public shelf with links and commissions, and the scene-mark preference; a new Beyond the writing surface section states what review, insights, goals, notifications, print, import, and admin are each for. assistant.md's status header now says shipped. Three stale schema comments fixed. CLAUDE.md gains the keep-design-docs- honest rule so the drift does not regrow. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Self-contained preview cards over the shipped CSS (styles/ is a symlink into src/lib/styles), one card per canonical primitive from the components sheet, each rendered in dark, light, and warm side by side. Marked with @DSCARD groups for syncing into a Claude Design design-system project; the README carries the sync steps and ground rules. Verified by rendering every card headless and checking the screenshots. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Latin subsets of Hanken Grotesk, Spectral, and JetBrains Mono (SIL OFL) copied from the fontsource packages the app loads, declared in fonts.css and imported by the kit scaffold, so previews render the actual letterforms instead of system fallbacks. README sync steps updated, including the symlink caveat found during the first push. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The Codex design project now holds the CSS, cards, and fonts, so the shared-context-plus-brief format collapses into four self-contained prompts, reordered to the agreed run order (primitives, navigation, secondary surfaces, landing) with delivery as pages in the project. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Adds primitives.css, loaded last, owning the modal, the empty state, the chip remove affordance, and the shared focus ring. Completes .btn (states plus btn-accept), gives .icon-btn a 28px .sm and a .danger tint, gives .seg a .seg-count, and adds the type ramp, --danger-contrast, and a per-theme --select-caret. Migrates the scoped duplicates onto them: the rv-btn family, rv-quick-btn, rb-btn, mini-btn, tool-btn, send-btn and pop-open become .btn/.icon-btn; rtabs, rv-filters, rv-mtabs and revision-filter-chip become .seg; the three hand-rolled modals share one panel; twelve empty-state spellings become .empty-state. Deletes the superseded CSS and the drift sheet's dead blocks. Behaviour is unchanged; e2e selectors follow the renames. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The modal primitive centres its panel, which made the palette's input drift as results changed height while typing. A .top modifier on the backdrop restores the 14vh anchor for overlays with changing content; the review modal and help stay centred, their content height is fixed. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Land the accepted navigation model: one app bar for every page Every page now wears the same bar - brand, path, tools - replacing the editor's .topbar, the pages' .page-shell .topbar with its .back-link, the print page's one-off bar, and .review-guest-bar. Three shells share it: author, guest, reader. The two contested decisions, as ratified. A place in the path is a menu: clicking the universe or story name opens everything that belongs to it, starting with "Go to the universe" / "Go to the story", settings included as a word rather than a glyph. There is no gear anywhere in the chrome. And the help modal is gone: the ? tool navigates to the help pages, lights up via aria-current while you are there, and returns to where you were when pressed again, so help is openable in another tab and never covers your work. Paths are built in $lib/chrome.ts so every screen spells the same destinations the same way. The theme tool cycles dark -> light -> warm through the existing theme.ts, persisting to the account when signed in and to localStorage for guests and readers; the avatar menu's theme item now walks the same cycle instead of a parallel light/dark flip. The mode strip is always four modes: at universe scope Write and Review open the universe's story list, and for a guest three are switched off in place, each case with one rendered line under the strip saying why. Deleted: HelpModal, TopBar, PageTopBar, PaletteButton, and the .topbar, .crumbs, .back-link, .breadcrumb, .save-status, .review-guest-bar and .universe-edit CSS. /docs is public now, because the guest and reader shells keep the help tool and neither has an account. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Reach the library through the bar's brand, not the deleted .brand The old bars carried .brand; the app bar's is .appbar-brand. This click sits past the export step, which the local suite cannot reach without MinIO, so only CI caught it. Selects by accessible name instead of by class. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Note the navigation model in TODO.md Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * Say where the story list is, not where the mock had it Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
… one creation pattern (#508) * Give the right pane one panel strip across every workspace view * Build the reading pages from the tokens, with one footer and the reader's theme * Give every collection one creation menu and retire the Session panel * Move the tests onto the new panels, menus and reading pages * Bring the help articles and the design docs up to the surfaces model * Keep the review panel's props in one place, and steady three specs * Note the pen-name-at-publish ask in the backlog * Give the theme cycle a third icon: the button shows where the click goes * Hide the review tab bar on desktop; it exists for narrow screens * Remove Accept all: a bulk apply can change more than is on screen The per-card accept stays. If bulk decisions come back they belong in a review toolbar that shows its scope first (backlog note added). * Never scroll the review manuscript sideways A suggestion ghost's padding can poke a few pixels past the measure and CodeMirror's scroller grew a horizontal scrollbar over it. The lines wrap, so sideways scroll has nothing legitimate to show. * Space the compose draft's textarea off its action row As an inline element its only gap was the baseline slack, which read as the buttons overlapping the field. * Draw the focused review mark's ring inside its box An outward ring on wrapped inline text rings every line fragment and collides with its own next line, and with the ghost beside a deletion. Inset ring with cloned fragments instead; the pulse animates the tint. The editor's ghost also gains the 3px gap the read surface already had. * Let a focused suggestion sit in justified prose The ghost's pre-wrap kept its preserved spaces rigid, dropping every line it touched out of justification; pre-line collapses them so they stretch, while a newline in the suggestion still breaks. All marks gain enough padding that the inset focus ring never sits on a glyph. * Slice the review marks so focus never moves the prose Cloned fragments gave every wrapped line the mark's padding and margin, which indented continuation lines - and only on focus, so the text jumped when a card was clicked. Slice keeps padding at the mark's true ends only: wrapped edges sit flush at the margins, justified lines keep their measure, and focusing changes paint alone. * Keep marked prose on the measure Three causes, one symptom each: an anchor that grabbed edge whitespace tinted it (render-side trim now leaves it out, the stored anchor is untouched); a space hanging at a justified line break painted its tint past the measure (the line clips it); and the mark's own edge padding pushed its text off the shared left edge (a matching negative margin hands the width back, so the box bleeds and the text does not move). * Say Cmd, not Ctrl, on Apple platforms The palette already accepted both modifiers; only the labels lied. A keys helper names the platform's modifier, and the app bar chip and the formatting tooltips settle on it after mount (SSR says Ctrl).
…gned-out page (#509) * Port the public surfaces: one shell for everything a visitor sees The fourth design-pass session. public.css is a new layer loaded last and the .landing-* block is gone from pages.css. One public shell now covers the landing page, sign-in, sign-up and every page an email link lands on: .public-surface over AppBar's fourth reduction (shell="public": brand linking home, theme and help, no path) and ReaderFooter's public reduction. AuthShell is the card inside that shell rather than a frame of its own. The landing page shows the workspace instead of describing it: a .ws-* figure drawn from tokens, so it is correct in all three themes, with a real three-way posture tablist carrying the same keyboard contract as PanelStrip, then four model statements in sentences. Sign-in keeps email and password, the passkey button and forgot-password. Sign-up keeps its fields and every mode and sent state. The open/closed switch is now mode-aware through signupOffered(): approval and open offer sign-up, invite and none do not, because a visitor with no code cannot finish one. New help article on self-hosting, so every handbook link on these pages reaches an article that exists. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Give invite mode its own account statement on the landing page The invite branch rendered the approval paragraph (ask and you get an answer) and then said requests are closed, which contradicts it. One paragraph per mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Link the sign-up page from the invite-mode text A code sometimes arrives without a link; the prose now carries one on the landing page and the sign-in page, noted in the design docs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Let the public text fill its boxes, and link the footer brand home The drop capped every prose block to a measure; inside the model cards and under the heading the box already bounds the line, so the caps only left dead space. Caps stay, loosened, on the two full-width prose blocks. The footer brand on public pages now links home like the bar's. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Preload route code on viewport, not hover Hover preloading inserted modulepreload links into the head mid-hover, and Safari and Firefox only recompute the cursor on mouse movement, so the hand cursor dropped to an arrow a moment after entering any link. Code now preloads when a link scrolls into view; data stays on hover, since a fetch does not touch the DOM. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Match the footer brand link exactly getByRole matches the accessible name by substring, so 'Codex' also resolved 'Reading in Codex' and the click failed strict mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Format the footer brand locator Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Save account Profile and Assistant settings on field exit The last two account sections with explicit save buttons join the autosave pattern the other four already use. One-shot actions (claim handle, enable publishing, test connection, discover models) keep their buttons. autosubmitForm skips data-no-autosave controls so the model filter box does not save; a discovery result now outlives the next action result so role picks after a discover keep the full list; removing a profile link saves itself. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Keep the alternating test name matching the shelf assertion core-flow reads the anonymous shelf name for the 'Tester' substring; 'E2E Retester' only contains it lowercased. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* Move story import into a modal with drag-and-drop Importing from the library no longer lands on the settings page next to the danger zone. The New menus and the settings Import block open a modal instead: pick or drop a file (zip, docx, epub), the preview runs at once, then confirm. The form posts to the target universe's existing actions from wherever the modal is mounted, so the server flow is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Drive the Word-manuscript import spec through the modal Missed when import-story.spec moved: this one now exercises the settings-page entry point. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The library card leads with the reader shelf's cover pattern: the uploaded artwork, or the title set on the cover blank. The library load gains cover_asset_id. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The mode strip drops Notes (Write / Plan / Review remain); the Notes page sits beside the modes with nothing lit and a line saying how to get there. The Write view's Notes panel is now always present, listing the story's notes with the open scene's first, and both Plan views gain a Notes panel for the open entry's scope. The command palette learns Story notes, Universe notes, and Quick note. Quick capture: Ctrl/Cmd+Alt+N floats a jot card over the editor; the first line becomes the title, Ctrl+Enter saves to the story's notes (attached to the open scene when there is one) through a new POST /api/notes, and focus goes straight back. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
An admin sets a per-user invite allowance from the accounts list (migration 0066, additive). Users with one get an Invites section on the account page: generate single-use codes against the allowance, copy the sign-up link, and revoke unused codes to free their slot. Codes redeem exactly like admin-minted ones, so an invited friend skips the approval queue but still confirms their email. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Claiming a handle or publishing an edition with no pen name set opens a prompt asking what name goes on the page, offering the display name to keep. The choice is stored as the pen name (setPenNameIfUnset, which never overwrites), so the public byline is always one the author chose and the prompt never returns. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The /@handle shelf now shows the owner their own header (bio, links, avatar, commissions) even while the profile is not public, with a note saying only they can see it. Visitors are unchanged. The account page links to the page from the address field. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The quick-note hint and the editor's TODO hint hardcoded Ctrl and Alt; they now read the platform labels from the existing keys helper, which gains altLabel beside modLabel. The shortcuts article's convention line covers Option too. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The articles write shortcuts with the PC labels; the docs page now swaps Ctrl+ for Cmd+ and Alt+ for Option+ for Apple readers, through appleShortcutLabels in the keys helper. The per-line '(Cmd on a Mac)' parentheticals go, and the shortcuts article's convention line says what the reader actually sees. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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.
One fix on top of v3.17.1: the help articles now render shortcut combos with the reader's own modifier labels - Cmd and Option on Apple platforms, Ctrl and Alt elsewhere - and the per-line "(Cmd on a Mac)" asides are gone (#522).
🤖 Generated with Claude Code