Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
213 commits
Select commit Hold shift + click to select a range
780cf59
Keep local preview URL until server response
zoltanhosszu Apr 1, 2026
866844a
Swap to error state DOM on error
zoltanhosszu Apr 1, 2026
69620b7
Test update
zoltanhosszu Apr 1, 2026
c219e8d
PR feedback
zoltanhosszu Apr 1, 2026
cf7a337
PR feedback 2
zoltanhosszu Apr 2, 2026
91de760
Test fix
zoltanhosszu Apr 2, 2026
a9625cd
PR feedback
zoltanhosszu Apr 2, 2026
2600b71
Stale-node guard
zoltanhosszu Apr 2, 2026
420e875
Regression test
zoltanhosszu Apr 2, 2026
3f68521
Clear format button
zoltanhosszu Apr 4, 2026
0d61791
Clear format tests
zoltanhosszu Apr 4, 2026
66d11b4
PR feedback
zoltanhosszu Apr 4, 2026
3b68378
Merge pull request #943 from basecamp/clear-formatting
zoltanhosszu Apr 6, 2026
49309ec
Extract functions
zoltanhosszu Apr 7, 2026
23e33a7
Merge pull request #931 from basecamp/image-upload-sizing
zoltanhosszu Apr 7, 2026
b407c1b
Keep cursor location when upload completes
zoltanhosszu Apr 2, 2026
2131051
Merge conflict resolution
zoltanhosszu Apr 7, 2026
5c0ea55
Update active_storage_mock.js
zoltanhosszu Apr 7, 2026
5dc9db2
Add a registerListener helper
samuelpecher Apr 1, 2026
3a9f25b
Add ListenerBin for listener handling
samuelpecher Apr 1, 2026
6c26ffc
Apply listener helpers to EditorElement
samuelpecher Apr 1, 2026
372d257
Apply listener helpers to CommandDispatcher
samuelpecher Apr 1, 2026
12c46b5
Apply listener helpers to PromptElement
samuelpecher Apr 1, 2026
0fb79c4
Apply listener helpers to ToolbarElement
samuelpecher Apr 1, 2026
3d6a92f
Apply listener helpers to Selection
samuelpecher Apr 2, 2026
174bd68
Apply listener helpers to TableTools
samuelpecher Apr 2, 2026
8834fff
Apply listener helpers to AttachmentDragAndDrop
samuelpecher Apr 2, 2026
129f816
Apply listener helpers to ToolbarDropdown and subclasses
samuelpecher Apr 2, 2026
07dea77
Apply listener helpers to TableController
samuelpecher Apr 2, 2026
89e2de5
Merge pull request #936 from basecamp/typing-during-upload
zoltanhosszu Apr 7, 2026
0b864e5
Apply listener helpers to CodeLanguagePicker
samuelpecher Apr 7, 2026
4d12a0f
Simplify with selection.nearestNodeOfType finder
samuelpecher Apr 7, 2026
edd019e
Simplify conditional language assignment
samuelpecher Apr 7, 2026
945ee77
Simplify language picker ordering
samuelpecher Apr 7, 2026
2ef7d8b
Fix XSS via unsanitized action-text-attachment content attribute (#903)
jorgemanrubia Apr 7, 2026
b9457a3
Use ActionText::Editor adapter on Rails 8.2+, fall back to monkey-pat…
jorgemanrubia Apr 7, 2026
003c3ac
Merge pull request #934 from basecamp/listener-tidy
samuelpecher Apr 7, 2026
a10d015
Unwrap link dialog form
zoltanhosszu Apr 7, 2026
3286bb7
Remove unused event
zoltanhosszu Apr 7, 2026
0bc0a99
PR feedback
zoltanhosszu Apr 7, 2026
4cab8d5
Adding test for Enter handling
zoltanhosszu Apr 7, 2026
476c2e5
Collapse link url getter with selection.nearestNodeOfType helper
samuelpecher Apr 7, 2026
11b8f5e
Add button getters
samuelpecher Apr 7, 2026
6f3344c
Support markdown shorthand --- for horizontal divider (#927)
diogovernier Apr 7, 2026
f78352e
Bump the lexical group with 16 updates (#942)
dependabot[bot] Apr 7, 2026
9a4b622
Merge pull request #945 from basecamp/unwrap-link-form
zoltanhosszu Apr 7, 2026
19ca66c
Direct host app bugs to basecamp/coworker's /bugs-fix skill
jorgemanrubia Apr 7, 2026
7481d2a
Tweak editor styling in docs
zoltanhosszu Apr 7, 2026
15d613c
Merge pull request #949 from basecamp/docs-editor-styling
zoltanhosszu Apr 7, 2026
2ae6110
Create bug-fix PRs in draft mode
jorgemanrubia Apr 7, 2026
e01ddeb
Prevent future bug by detecting tag with $hasUpdateTag
samuelpecher Apr 7, 2026
51b16ed
Unify insertion APIs
samuelpecher Apr 7, 2026
70af2cf
get selection
samuelpecher Apr 7, 2026
a22aff9
Introduce NodeInserter
samuelpecher Apr 7, 2026
f7b453c
Split out NodeInserters for RangeSelection and NodeSelection
samuelpecher Apr 7, 2026
0746fea
Handle ShadowRoot insertion separately
samuelpecher Apr 7, 2026
6a23f54
Fix pasting into blockquote
samuelpecher Mar 23, 2026
3638c39
Fix multi-line selection creating separate code blocks per line
samuelpecher Mar 23, 2026
f850a4c
Unwrap container elements before applying code block format
samuelpecher Mar 23, 2026
71ad553
Simplify and handle non-element top-level nodes
samuelpecher Apr 7, 2026
9bac75a
It's all just node insertion
samuelpecher Apr 7, 2026
6c61a2f
Code blocks are ok in block quotes
samuelpecher Apr 8, 2026
2f226b3
Merge pull request #911 from basecamp/fix-paste-quote-linebreak
samuelpecher Apr 8, 2026
ed2bcaf
Merge pull request #912 from basecamp/fix-multiline-code-block
samuelpecher Apr 8, 2026
814789e
Prevent extension toolbar buttons from duplicating on reconnect (#958)
jorgemanrubia Apr 9, 2026
54432b1
Show file icon for freshly uploaded PDFs, poll for preview (#956)
jorgemanrubia Apr 9, 2026
d46acec
Split soft line breaks into paragraphs before inserting lists (#946)
jorgemanrubia Apr 9, 2026
b8993b8
import Prismjs with grammars into external helper
samuelpecher Apr 8, 2026
f3a2ccc
Test grammars are included
samuelpecher Apr 9, 2026
30c8dbc
Remove deprecated legacy export
samuelpecher Apr 9, 2026
65bc4ef
Enable editable captions for video attachments (#950)
jorgemanrubia Apr 9, 2026
29a994b
Convert empty first list item to paragraph on backspace (#948)
jorgemanrubia Apr 9, 2026
d658e6d
Fix code blocks only allowing one highlight at a time (#955)
jorgemanrubia Apr 9, 2026
e995ece
Click attachments after upload (#957)
samuelpecher Apr 9, 2026
f8f5496
Build sanitizer allowlist dynamically (#909)
zachasme Apr 9, 2026
2336c03
Fix @mentions menu rendering out of bounds near right edge (#913)
samuelpecher Apr 9, 2026
1b97d82
Bump version
jorgemanrubia Apr 9, 2026
898255e
Bump version
jorgemanrubia Apr 9, 2026
213e84e
Configure Action Text adapter as :lexxy automatically (#962)
jorgemanrubia Apr 9, 2026
bfa9146
Bump version
jorgemanrubia Apr 9, 2026
a164809
v0.9.5-beta
jorgemanrubia Apr 9, 2026
a1134bf
Allow inserting text before a code block
jorgemanrubia Apr 7, 2026
63b9232
Revert placing provisional paragraphs around code blocks
samuelpecher Apr 9, 2026
2e65fad
Don't change selection
samuelpecher Apr 9, 2026
ae3bc29
Use $isAtNodeStart helper
samuelpecher Apr 9, 2026
1172106
Use `is()` for identity checks and collapse logic
samuelpecher Apr 9, 2026
2569131
Import Lexical default prism languages
samuelpecher Apr 9, 2026
bb431e2
Support Kotlin
samuelpecher Apr 9, 2026
fbc3836
Auto-trigger mass-bug-fixing skill for multi-bug requests
jorgemanrubia Apr 10, 2026
84a1de7
Fix crash when applying list formatting to a selected attachment (#967)
jorgemanrubia Apr 10, 2026
30009da
Fix text drag crash in attachment drag handler (#969)
jorgemanrubia Apr 10, 2026
d8be7be
Fix input lag in prompt/mention system (#968)
jorgemanrubia Apr 10, 2026
bf65fd7
Bump version
jorgemanrubia Apr 10, 2026
b20082c
Update beta language in README
jorgemanrubia Apr 10, 2026
a3b6729
Fix over-sanitization of custom attachment contents (#966)
samuelpecher Apr 10, 2026
39a00ed
Bump version
jorgemanrubia Apr 10, 2026
9d33b82
Bump the github-actions group with 3 updates (#941)
dependabot[bot] Apr 10, 2026
356f69b
Fix link dialog URL value
zoltanhosszu Apr 13, 2026
000615f
Add test for regression
zoltanhosszu Apr 13, 2026
bbb540a
Empty string instead of null
zoltanhosszu Apr 13, 2026
26b2e37
Merge pull request #974 from basecamp/link-fix
zoltanhosszu Apr 13, 2026
d129358
Update filtering method
zoltanhosszu Apr 13, 2026
459ace2
Tests for expected prompt filtering logic
zoltanhosszu Apr 13, 2026
a0dfd96
Simplify with regex
zoltanhosszu Apr 13, 2026
8499efa
PR feedback
zoltanhosszu Apr 13, 2026
7cef735
Merge pull request #975 from basecamp/prompt-filtering
zoltanhosszu Apr 13, 2026
5d9063c
v0.9.7-beta
jorgemanrubia Apr 10, 2026
af2805b
Bump version
jorgemanrubia Apr 13, 2026
230ad06
Bump version
jorgemanrubia Apr 13, 2026
20c9558
Open links in editor using ctrl/cmd+click
zachasme Apr 14, 2026
37053fd
Merge pull request #976 from basecamp/link-opener
zachasme Apr 16, 2026
0b379e7
Fix toolbar focus
zoltanhosszu Apr 16, 2026
636cd77
Update command_dispatcher.js
zoltanhosszu Apr 16, 2026
7f722a1
Update toolbar.js
zoltanhosszu Apr 16, 2026
ae6c275
Merge pull request #979 from basecamp/fix-toolbar-focus
zoltanhosszu Apr 16, 2026
3d3b62e
Merge pull request #980 from basecamp/fix-link-change
zoltanhosszu Apr 16, 2026
77e0dea
Allow value
zoltanhosszu Apr 16, 2026
5b6c52b
Update engine.rb
zoltanhosszu Apr 16, 2026
0591414
Move attr registration to proper place
zoltanhosszu Apr 16, 2026
bf02aa6
Update block_formatting.test.js
zoltanhosszu Apr 16, 2026
447b7a2
Add value to all list tests
zoltanhosszu Apr 16, 2026
07026b7
Test coverage for indented list numbering
zoltanhosszu Apr 17, 2026
fb215eb
Skip turbo:before-cache reset for editors inside turbo-permanent elem…
rosa Apr 15, 2026
8074dae
Merge pull request #981 from basecamp/ol-value
zoltanhosszu Apr 17, 2026
ec22748
Cache Playwright browser binaries in CI (#970)
jorgemanrubia Apr 17, 2026
5eb27ff
Batch DOM reads and writes during editor initialization (#982)
jorgemanrubia Apr 17, 2026
c10a50a
Bump version
jorgemanrubia Apr 17, 2026
a55d687
Reduce init-time style recalc: contained resolver root, content conta…
jorgemanrubia Apr 17, 2026
08e24eb
v0.9.9-beta
jorgemanrubia Apr 17, 2026
0bfb489
Bump version
jorgemanrubia Apr 17, 2026
4620342
Helpers and config: block helpers, list-item lookup, markdown list sh…
jondkinney Apr 17, 2026
5a47e4e
Nodes: attachment lifecycle, audio/video players, collapsed card view
jondkinney Apr 17, 2026
7beed6f
Block-select extension: multi-block selection, movement, formatting
jondkinney Apr 17, 2026
459c674
Block actions menu: Cmd+/ popover with Turn into / Color / Duplicate …
jondkinney Apr 17, 2026
f3e6991
Block drag-and-drop: handle, ghost, drop targeting
jondkinney Apr 17, 2026
2743e30
Preview modal and attachment controls
jondkinney Apr 17, 2026
e0adf63
Extensions and dispatcher: wire block-select into formatting and tables
jondkinney Apr 17, 2026
8594d2e
Toolbar, dropdowns, and language picker: integrate block-select
jondkinney Apr 17, 2026
87afb25
Editor element: register block-select extension and element index
jondkinney Apr 17, 2026
91699e4
CSS: block handles, drop targets, block actions menu, preview modal
jondkinney Apr 17, 2026
3025d0e
Server-side: attachment helpers, blob partial, engine wiring, build s…
jondkinney Apr 17, 2026
bc7637f
Tests: block-select, drag-and-drop, movement, wrapped-block suites
jondkinney Apr 17, 2026
62bdb67
Tests: helper and existing-suite updates for block-editing integration
jondkinney Apr 17, 2026
b2757ae
Docs: audit, regression-test plan, group-movement plan, merge plan
jondkinney Apr 17, 2026
da9cb4f
Lint: drop unused import, getter, and directive in block_selection_ex…
jondkinney Apr 17, 2026
5ffea13
PLAN: upstream PR readiness checklist with resume-anywhere details
jondkinney Apr 17, 2026
765742e
CSS: namespace block-select classes under lexxy-editor__*
jondkinney Apr 17, 2026
cb782a4
Block-select: O(1) key-to-index lookup for delete/duplicate/move
jondkinney Apr 17, 2026
d538985
Attachment: cache SVG object URLs by src; drop poll cache-buster
jondkinney Apr 17, 2026
768efad
Ruby: move icons to assets, register helpers via controller, drop ico…
jondkinney Apr 17, 2026
ada830e
Sanitize: drop <embed>/download/target from allowlist, document var()…
jondkinney Apr 17, 2026
b2a6b94
Tests: extract shared block-editing helpers (stripDynamicAttrs, asser…
jondkinney Apr 17, 2026
9bb957c
Extensions: add get(klass) helper, replace inline instanceof lookups
jondkinney Apr 17, 2026
61e08a6
Helpers: move last-used-color persistence to storage_helper
jondkinney Apr 17, 2026
336473f
Preview: move dialog_builder + playback_sync under src/elements/preview/
jondkinney Apr 17, 2026
92911db
Dead code: drop dispatchCustomEvent, inline block-drag element creation
jondkinney Apr 17, 2026
dac5e9e
Attachment nodes: unify backgroundUpdateTags on the parent class
jondkinney Apr 17, 2026
04ad404
Helpers: consolidate extractFileExtension
jondkinney Apr 17, 2026
2daa0f4
Polish: private #handlePreviewEvent, explain stale-key catches
jondkinney Apr 17, 2026
a569776
Attachment node: extract #wrapInPreviewView helper
jondkinney Apr 17, 2026
5560a73
CommandDispatcher: unify COMMANDS + BLOCK_FORMAT_COMMANDS into one map
jondkinney Apr 17, 2026
fdb0d9c
Blob partial: split into per-content-type sub-partials
jondkinney Apr 17, 2026
c9c2343
Block-select: reuse navigable-keys list within an arrow-key handler
jondkinney Apr 17, 2026
51b30be
Block-select: track decorated elements in Sets; drop root-wide queryS…
jondkinney Apr 17, 2026
acb6f9e
PLAN: update audit checklist progress
jondkinney Apr 17, 2026
a80d723
Tests: restore stripDynamicAttrs imports missed by earlier dedup
jondkinney Apr 17, 2026
c1af437
Tests: pin Code-button locator to exact match
jondkinney Apr 17, 2026
02c740b
Block-drag: cache root + list snap-point positions during a drag
jondkinney Apr 17, 2026
a74bcd9
PLAN: mark P2-1 and P2-8 deferred with rationale
jondkinney Apr 17, 2026
be1b453
Block-drag: extract DragGhost into src/editor/block_drag_and_drop/gho…
jondkinney Apr 17, 2026
77e74cc
Block-drag: extract AutoScroll into block_drag_and_drop/autoscroll.js
jondkinney Apr 17, 2026
85b9f48
Block-drag: extract DropIndicator DOM lifecycle
jondkinney Apr 17, 2026
c9917da
Block-drag: extract pure geometry helpers
jondkinney Apr 17, 2026
61cd6eb
Block-select: extract pure highlight CSS helpers
jondkinney Apr 17, 2026
a415df7
PLAN: record P0-2/P0-3 partial-split status
jondkinney Apr 17, 2026
8dcbcb5
Relocate block-select subsystem to src/editor/block_selection/
jondkinney Apr 17, 2026
2a92ea4
Block-select: extract SelectionHistory into its own module
jondkinney Apr 17, 2026
f1b0c76
Block-select: extract WrappedOriginTracker
jondkinney Apr 17, 2026
4d80aa8
Block-select: extract bullet marker color sync transform
jondkinney Apr 17, 2026
44e7c84
Block-select: module-roster header + format/highlight section marker
jondkinney Apr 17, 2026
8cb5d7e
Contents: use basecamp's getListItemNode helper instead of #findParen…
jondkinney Apr 17, 2026
a011342
Block-helpers: extract getNodeKeyFromElement, drop 3 duplicates
jondkinney Apr 17, 2026
ec313b1
Block-select: use getListItemNode for two simple parent walks
jondkinney Apr 17, 2026
02ad5dc
Block-drag: delegate #getNodeDepth to $getListDepth from @lexical/list
jondkinney Apr 17, 2026
9772df0
Block-select: use getListItemNode in #shouldRetainHighlightFromParent
jondkinney Apr 17, 2026
d7225a7
Tests: click figure.attachment img for webkit selection parity
jondkinney Apr 17, 2026
7863a2f
Tests: strip Lexical's <li value="N"> in block-editing assertions
jondkinney Apr 17, 2026
032e8dc
Block-select: fix #isPromptOpen selector to detect visible popover
jondkinney Apr 17, 2026
c239eed
Tests: hide attachment-controls overlay so attachment click lands
jondkinney Apr 17, 2026
8bb7fcb
Tests: disable block-handles in mentions right-edge popover test
jondkinney Apr 17, 2026
bd321c1
Tests: widen viewport for mentions right-edge popover test
jondkinney Apr 17, 2026
77c9a18
Preview modal: scale SVGs to fill the container
jondkinney Apr 17, 2026
482b63e
Preview dispatch: unify attachment detail via shared helper
jondkinney Apr 17, 2026
baea281
PLAN doc: refresh inventory, stats, and sanitization allowlist
jondkinney Apr 17, 2026
34019ea
Block actions menu: contextual "Wrap in..." labels for wrap-only targets
jondkinney Apr 19, 2026
c0c3010
Block-select: movement, selection-sync, and parent-height refinements
jondkinney Apr 19, 2026
4d1dda1
Selection highlight: no layout shift + consistent wrapped-block rhythm
jondkinney Apr 19, 2026
dc1d375
PLAN doc: refresh for tonight's selection-sync and spacing changes
jondkinney Apr 19, 2026
3b372d3
Block-select: close visible gap for isolated leaves via dynamic ::aft…
jondkinney Apr 19, 2026
3ed2bd5
Block-select: halfway-split extension when isolated-leaf neighbor is …
jondkinney Apr 19, 2026
12f06f6
Block-select: pre-determined halfway leaf reach for consistent highli…
jondkinney Apr 19, 2026
2cafd35
Block-select: extend leaf-reach to attachments and galleries
jondkinney Apr 19, 2026
d1904ad
Block-select: drop integer rounding on leaf reach to hit exact 4px gap
jondkinney Apr 19, 2026
4e0e3bd
Block-select: skip hidden provisional paragraphs when finding adjacen…
jondkinney Apr 19, 2026
9b9b839
Block-select: per-pair target gap for leaf reach
jondkinney Apr 19, 2026
8d538c9
PLAN doc: refresh for leaf-reach subsystem and provisional-paragraph …
jondkinney Apr 19, 2026
132e79f
PLAN doc: refresh for per-pair target gap
jondkinney Apr 19, 2026
5bb8417
PLAN doc: correct previewModal default and blob-partial override guid…
jondkinney Apr 19, 2026
dce8662
PLAN doc: audit file inventory against current line counts
jondkinney Apr 19, 2026
c351634
Block-select: inline single-caller #removeQuoteWrapper/#removeListWra…
jondkinney Apr 19, 2026
600ae52
PLAN doc: refresh stats after inlining wrapper methods
jondkinney Apr 19, 2026
a96eb0b
Update plan doc
jondkinney Apr 19, 2026
0aa5eb9
Tests: focus at end-of-text on first interaction, not center-click
jondkinney Apr 19, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .claude/skills/mass-bug-fixing/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ name: mass-bug-fixing
description: |
Process multiple bugs from a Fizzy board (or GitHub issues) in parallel.
Uses worktree agents to reproduce, fix, test, create PRs, and comment on cards.
invocation: user
invocation: auto_and_user
auto_trigger: when the user asks to fix more than one bug at a time (e.g., provides multiple bug URLs, card numbers, or issue references)
user_invocation: /mass-bug-fixing
---

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/benchmarks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: "20"
node-version: "22"
cache: "yarn"

- name: Install JavaScript dependencies
Expand Down
46 changes: 38 additions & 8 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,15 @@ jobs:
persist-credentials: false

- name: Set up Ruby
uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0
uses: ruby/setup-ruby@3ff19f5e2baf30647122352b96108b1fbe250c64 # v1.299.0
with:
ruby-version: .ruby-version
bundler-cache: true

- name: Set up Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
node-version: '22'
cache: 'yarn'

- name: Install JavaScript dependencies
Expand Down Expand Up @@ -73,7 +73,7 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
node-version: '22'
cache: 'yarn'

- name: Install JavaScript dependencies
Expand All @@ -87,6 +87,19 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read

strategy:
fail-fast: false
matrix:
include:
- name: "Rails 8.1 (no adapter)"
use_legacy_rails: "true"
- name: "Rails main (with adapter)"
use_legacy_rails: ""

env:
USE_RAILS_WITHOUT_ACTION_TEXT_ADAPTER: ${{ matrix.use_legacy_rails }}

steps:
- name: Install packages
run: sudo apt-get update && sudo apt-get install --no-install-recommends -y build-essential git libyaml-dev pkg-config google-chrome-stable mupdf build-essential ffmpeg groff libreoffice-writer libreoffice-impress libreoffice-calc mupdf-tools libvips zip
Expand All @@ -97,15 +110,16 @@ jobs:
persist-credentials: false

- name: Set up Ruby
uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0
uses: ruby/setup-ruby@3ff19f5e2baf30647122352b96108b1fbe250c64 # v1.299.0
with:
ruby-version: .ruby-version
bundler-cache: true
cache-version: ${{ matrix.name }}

- name: Set up Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
node-version: '22'
cache: 'yarn'

- name: Install JavaScript dependencies
Expand All @@ -125,7 +139,7 @@ jobs:
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
if: failure()
with:
name: screenshots
name: screenshots-${{ matrix.name }}
path: ${{ github.workspace }}/test/dummy/tmp/screenshots
if-no-files-found: ignore

Expand All @@ -147,15 +161,31 @@ jobs:
- name: Set up Node.js
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
with:
node-version: '20'
node-version: '22'
cache: 'yarn'

- name: Install JavaScript dependencies
run: yarn install --frozen-lockfile

- name: Install Playwright browsers
- name: Get Playwright version
id: playwright-version
run: echo "version=$(npx playwright --version)" >> "$GITHUB_OUTPUT"

- name: Cache Playwright browsers
id: playwright-cache
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
with:
path: ~/.cache/ms-playwright
key: playwright-${{ matrix.browser }}-${{ steps.playwright-version.outputs.version }}

- name: Install Playwright browser
if: steps.playwright-cache.outputs.cache-hit != 'true'
run: npx playwright install --with-deps ${{ matrix.browser }}

- name: Install Playwright system deps
if: steps.playwright-cache.outputs.cache-hit == 'true'
run: npx playwright install-deps ${{ matrix.browser }}

- name: Run Playwright tests
run: yarn test:browser:${{ matrix.browser }}

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ jobs:
persist-credentials: false

- name: Setup Ruby
uses: ruby/setup-ruby@319994f95fa847cf3fb3cd3dbe89f6dcde9f178f # v1.295.0
uses: ruby/setup-ruby@3ff19f5e2baf30647122352b96108b1fbe250c64 # v1.299.0
with:
ruby-version: '3.3'
bundler-cache: true
working-directory: docs

- name: Setup Pages
id: pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5.0.0
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0

- name: Build with Jekyll
run: bundle exec jekyll build --baseurl "${STEPS_PAGES_OUTPUTS_BASE_PATH}"
Expand All @@ -63,4 +63,4 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
/test/browser/playwright-report/
/test/browser/blob-report/

Gemfile.lock

# Jekyll docs
/docs/_site/
/docs/.jekyll-cache/
Expand Down
6 changes: 4 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,14 @@ When changing how Lexxy formats or serializes content (new inline styles, node t

## Fixing Bugs

**Important:** Some bugs filed against Lexxy are actually bugs in the host application (e.g., BC5 modal behavior, server-side preview rendering, Turbo interactions). When a bug's root cause is in a 37signals app rather than in Lexxy itself, use the `/bugs-fix` skill from `basecamp/coworker` to fix it in the appropriate app repo (e.g., `~/Work/basecamp/bc3`). The workflow below applies only to bugs whose root cause is in Lexxy.

Follow this mandatory workflow. Every step must complete before moving to the next.

1. **Classify** — Determine if the bug is a **core editing bug** (JS behavior: typing, cursor, selection, formatting, paste, toolbar, nodes, extensions) or a **system-level bug** (e.g., Action Text, uploads, Trix conversion, persistence, prompt/SGID resolution, Turbo).
1. **Classify** — Determine if the bug is a **core editing bug** (JS behavior: typing, cursor, selection, formatting, paste, toolbar, nodes, extensions), a **system-level bug** (e.g., Action Text, uploads, Trix conversion, persistence, prompt/SGID resolution, Turbo), or a **host app bug** (e.g., BC5 modal/composer behavior, server-side preview rendering, Turbo frame interactions). Host app bugs should be fixed in the app repo using `/bugs-fix` from `basecamp/coworker`, not here.
2. **Reproduce** — Use `/bugs-reproducer` to write a failing test. This skill is ONLY for reproduction — do not investigate fixes or modify source code during this step. Core editing bugs go to Playwright (`test/browser/tests/`), system-level bugs go to Capybara (`test/system/`). Write the test, run it, and **confirm it fails before touching any source code.** A test that hasn't been seen failing proves nothing — it could be passing for the wrong reason. The failing test is your evidence that the bug is real. Do NOT skip this step even if the root cause seems obvious. If you have a justified reason to skip (e.g., the bug is purely visual and untestable), state the justification explicitly before proceeding.
3. **Fix** — Now investigate the root cause and work on the fix until the reproduction test passes.
4. **Test** — Ensure a regression test covers the bug. If you reproduced with Playwright or Capybara in step 2, you already have it. If you used Selenium as a fallback, write a proper test now. Then run the full test suite (`yarn test:browser` for Playwright, `bin/rails test:all` for Capybara) to discard regressions. **Always run `yarn lint` after making changes and fix any lint errors before committing.**
5. **PR & Copilot review** — Push the branch, create a PR, and request a GitHub Copilot review (`gh api repos/<owner>/<repo>/pulls/<number>/requested_reviewers -f "reviewers[]=copilot-pull-request-reviewer[bot]"`). When the review arrives, reply to each comment on GitHub. For actionable feedback (real bugs, internal API misuse, flaky test patterns), write a test that validates the issue first, then fix it. Decline cosmetic or low-value suggestions with a brief rationale.
5. **PR & Copilot review** — Push the branch, create a **draft** PR (`gh pr create --draft`), and request a GitHub Copilot review (`gh api repos/<owner>/<repo>/pulls/<number>/requested_reviewers -f "reviewers[]=copilot-pull-request-reviewer[bot]"`). When the review arrives, reply to each comment on GitHub. For actionable feedback (real bugs, internal API misuse, flaky test patterns), write a test that validates the issue first, then fix it. Decline cosmetic or low-value suggestions with a brief rationale.
6. **Validate** — Run `/manually-validate-fix <pr-number>` to validate the fix against both production (bug reproduces) and local (bug fixed). This step is mandatory after every PR — it catches cases where the automated test passes but the actual user-facing behavior is still broken.
7. **Learn** — If the bug revealed a **family of bugs** (an architectural pattern or subsystem that produces recurring issues), update the "Common Bug Patterns" section in `/bugs-reproducer` (`.claude/skills/bugs-reproducer.md`). Each entry should describe a class of bugs, not an individual fix. Good: "Decorator node navigation" (a whole category). Bad: "Backtick shortcut only works one direction" (a single bug). Don't add notes about specific bugs — that's what the tests and commit messages are for.
Loading
Loading