proseview 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. proseview-0.1.0/LICENSE +21 -0
  2. proseview-0.1.0/PKG-INFO +376 -0
  3. proseview-0.1.0/README.md +341 -0
  4. proseview-0.1.0/proseview/__init__.py +7 -0
  5. proseview-0.1.0/proseview/__main__.py +7 -0
  6. proseview-0.1.0/proseview/cli.py +359 -0
  7. proseview-0.1.0/proseview/codex_app_server.py +375 -0
  8. proseview-0.1.0/proseview/config.py +248 -0
  9. proseview-0.1.0/proseview/discuss.py +2138 -0
  10. proseview-0.1.0/proseview/editor.py +66 -0
  11. proseview-0.1.0/proseview/generator.py +629 -0
  12. proseview-0.1.0/proseview/goals.py +133 -0
  13. proseview-0.1.0/proseview/highlights.py +227 -0
  14. proseview-0.1.0/proseview/history.py +374 -0
  15. proseview-0.1.0/proseview/lexical.py +298 -0
  16. proseview-0.1.0/proseview/related.py +96 -0
  17. proseview-0.1.0/proseview/repo.py +516 -0
  18. proseview-0.1.0/proseview/scenes.py +451 -0
  19. proseview-0.1.0/proseview/server.py +1918 -0
  20. proseview-0.1.0/proseview/templates/assets/app.css +1841 -0
  21. proseview-0.1.0/proseview/templates/assets/js/00-state.js +108 -0
  22. proseview-0.1.0/proseview/templates/assets/js/10-prose-indicators.js +169 -0
  23. proseview-0.1.0/proseview/templates/assets/js/15-search.js +665 -0
  24. proseview-0.1.0/proseview/templates/assets/js/20-theme-font-charts.js +298 -0
  25. proseview-0.1.0/proseview/templates/assets/js/30-router-modal.js +420 -0
  26. proseview-0.1.0/proseview/templates/assets/js/40-prose-editor.js +237 -0
  27. proseview-0.1.0/proseview/templates/assets/js/50-discard-confirm.js +162 -0
  28. proseview-0.1.0/proseview/templates/assets/js/60-selection.js +1113 -0
  29. proseview-0.1.0/proseview/templates/assets/js/65-ai-proposals.js +805 -0
  30. proseview-0.1.0/proseview/templates/assets/js/68-discuss.js +1236 -0
  31. proseview-0.1.0/proseview/templates/assets/js/70-terminal.js +1315 -0
  32. proseview-0.1.0/proseview/templates/assets/js/80-sidebar-init.js +171 -0
  33. proseview-0.1.0/proseview/templates/index.html.j2 +653 -0
  34. proseview-0.1.0/proseview/templates/vendor/README.md +21 -0
  35. proseview-0.1.0/proseview/templates/vendor/chart.js +14 -0
  36. proseview-0.1.0/proseview/templates/vendor/chartjs-plugin-annotation.js +7 -0
  37. proseview-0.1.0/proseview/templates/vendor/marked.js +6 -0
  38. proseview-0.1.0/proseview/templates/vendor/xterm-addon-fit.js +8 -0
  39. proseview-0.1.0/proseview/templates/vendor/xterm.css +218 -0
  40. proseview-0.1.0/proseview/templates/vendor/xterm.js +8 -0
  41. proseview-0.1.0/proseview/watch.py +163 -0
  42. proseview-0.1.0/proseview.egg-info/PKG-INFO +376 -0
  43. proseview-0.1.0/proseview.egg-info/SOURCES.txt +64 -0
  44. proseview-0.1.0/proseview.egg-info/dependency_links.txt +1 -0
  45. proseview-0.1.0/proseview.egg-info/entry_points.txt +2 -0
  46. proseview-0.1.0/proseview.egg-info/requires.txt +10 -0
  47. proseview-0.1.0/proseview.egg-info/top_level.txt +1 -0
  48. proseview-0.1.0/pyproject.toml +74 -0
  49. proseview-0.1.0/setup.cfg +4 -0
  50. proseview-0.1.0/tests/test_app_refresh.py +85 -0
  51. proseview-0.1.0/tests/test_app_selection.py +41 -0
  52. proseview-0.1.0/tests/test_bundling.py +415 -0
  53. proseview-0.1.0/tests/test_cli.py +177 -0
  54. proseview-0.1.0/tests/test_codex_app_server.py +179 -0
  55. proseview-0.1.0/tests/test_config.py +180 -0
  56. proseview-0.1.0/tests/test_discuss.py +261 -0
  57. proseview-0.1.0/tests/test_discuss_manager.py +1102 -0
  58. proseview-0.1.0/tests/test_editor.py +82 -0
  59. proseview-0.1.0/tests/test_generator.py +512 -0
  60. proseview-0.1.0/tests/test_goals.py +116 -0
  61. proseview-0.1.0/tests/test_highlights.py +247 -0
  62. proseview-0.1.0/tests/test_history.py +178 -0
  63. proseview-0.1.0/tests/test_related.py +46 -0
  64. proseview-0.1.0/tests/test_repo.py +300 -0
  65. proseview-0.1.0/tests/test_server.py +288 -0
  66. proseview-0.1.0/tests/test_watch.py +84 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ari Saif
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,376 @@
1
+ Metadata-Version: 2.4
2
+ Name: proseview
3
+ Version: 0.1.0
4
+ Summary: A local dashboard and AI harness for Markdown-first novel repositories.
5
+ Author: Ari Saif
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/ourarash/proseview
8
+ Project-URL: Source, https://github.com/ourarash/proseview
9
+ Project-URL: Issues, https://github.com/ourarash/proseview/issues
10
+ Keywords: writing,novel,markdown,dashboard,lexical-analysis,prose
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Environment :: Console
13
+ Classifier: Environment :: Web Environment
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: MacOS :: MacOS X
17
+ Classifier: Operating System :: POSIX :: Linux
18
+ Classifier: Programming Language :: Python :: 3
19
+ Classifier: Programming Language :: Python :: 3.11
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Text Processing :: Markup
23
+ Requires-Python: >=3.11
24
+ Description-Content-Type: text/markdown
25
+ License-File: LICENSE
26
+ Requires-Dist: Jinja2>=3.1
27
+ Requires-Dist: PyYAML>=6.0
28
+ Provides-Extra: dev
29
+ Requires-Dist: pytest>=7; extra == "dev"
30
+ Provides-Extra: e2e
31
+ Requires-Dist: pytest>=7; extra == "e2e"
32
+ Requires-Dist: playwright>=1.44; extra == "e2e"
33
+ Requires-Dist: pytest-playwright>=0.5; extra == "e2e"
34
+ Dynamic: license-file
35
+
36
+ # Proseview
37
+
38
+ > A local dashboard and AI harness for novelists who write in Markdown. โœ๏ธ
39
+
40
+ Proseview reads your manuscript folder, gives you a writer-grade view of
41
+ its structure and prose, and turns the same surface into a place where you
42
+ can read, edit, annotate, and bring an AI assistant to any paragraph
43
+ without leaving the page.
44
+
45
+ It runs entirely on your machine. No cloud, no telemetry, no lock-in. Your
46
+ files stay where they are.
47
+
48
+ [![CI](https://github.com/ourarash/proseview/actions/workflows/ci.yml/badge.svg)](https://github.com/ourarash/proseview/actions/workflows/ci.yml)
49
+ ![status](https://img.shields.io/badge/status-alpha-orange)
50
+ ![python](https://img.shields.io/badge/python-3.11%2B-blue)
51
+ ![platform](https://img.shields.io/badge/platform-macOS%20%7C%20Linux-lightgrey)
52
+ ![license](https://img.shields.io/badge/license-MIT-green)
53
+
54
+ ![The Proseview dashboard: word-count goal, writing streak, and recently modified files](docs/images/dashboard.png)
55
+
56
+ ## ๐Ÿ“ธ A look around
57
+
58
+ ### Read and revise, with editorial passes on
59
+
60
+ Nine prose passes highlight repetition, passive voice, filter verbs and more,
61
+ right on the page you are reading.
62
+
63
+ ![A scene open in the reading view with four highlight passes enabled](docs/images/scene-highlights.png)
64
+
65
+ ### Search the whole repository
66
+
67
+ `Mod-K` from anywhere. File paths, scene metadata, TODOs, notes, and prose,
68
+ grouped by kind.
69
+
70
+ ![The search palette open over a scene, showing file, scene, and prose matches](docs/images/search.png)
71
+
72
+ ### Analytics that mean something
73
+
74
+ ![Character presence, sentence-rhythm bands, setting stickiness, and character co-occurrence charts](docs/images/analytics.png)
75
+
76
+ > Screenshots use the bundled `fixtures/demo-repo` (four scenes), so the charts
77
+ > are deliberately small. Your book fills them in.
78
+
79
+ ## โœจ What you get
80
+
81
+ - ๐Ÿ“Š **Dashboard.** Word count, chapter pacing, lexical health (MATTR /
82
+ MTLD), sentence-rhythm variance, character presence, location
83
+ stickiness, character co-occurrence, plus a sortable scene table.
84
+ - ๐Ÿ“– **Reading view.** Open a scene as a typographic page with a real
85
+ reader font. The dashboard chrome gets out of the way.
86
+ - โœ๏ธ **WYSIWYG editor.** ProseMirror-backed. Same surface as the reading
87
+ view, just with `Edit` toggled on. Mod-S saves. Conflict guard checks
88
+ the file mtime so a concurrent change in your editor never gets
89
+ silently overwritten.
90
+ - ๐ŸŽจ **Editorial highlights.** Toggle nine prose passes on top of any
91
+ scene: repetition, passive voice, filter verbs, crutch words,
92
+ hyperbole, lyrical reach, sensory density, comedy beats, first-person
93
+ rate. Each pass is a single click.
94
+ - ๐Ÿ—’๏ธ **Inline TODOs and Notes.** Select a passage, drop a `TODO` or a
95
+ tagged `NOTE` (continuity / character / theme / question), and it
96
+ lands in the file as a Markdown comment. Survives in git.
97
+ - ๐Ÿค– **AI on the selection.** Send the highlighted passage to Codex,
98
+ Claude, or Gemini in one click. An in-browser terminal hosts the
99
+ conversation; the agent can see the file, the selection, and your
100
+ repo. Your tools, your prompts.
101
+ - ๐Ÿ’ฌ **Discuss with Codex.** Open a document-aware conversation beside
102
+ any scene or supported repository text file. Proseview sends the current
103
+ document automatically and only adds selections, files, or folders you
104
+ explicitly attach. Safe progress summaries, plans, tool activity, approval
105
+ requests, and streamed answers stay visible while you read.
106
+ - ๐Ÿงฐ **In-browser terminal.** xterm.js wired to a real PTY. Run `codex`,
107
+ `claude`, or any shell command without leaving the dashboard. Tabs
108
+ persist across page reloads.
109
+ - ๐Ÿ” **Live reload.** Save a file in your editor and the dashboard
110
+ picks up the change over Server-Sent Events. No manual refresh.
111
+ - ๐Ÿ”— **Deep links.** Every scene and file has a URL. Copy the address
112
+ bar to share or revisit a view. Back / forward work.
113
+ - ๐Ÿ”Ž **Repository search.** Press Mod-K or choose Search from any dashboard,
114
+ scene, or file view. File paths come from one repository-wide inventory;
115
+ opening a result loads its preview lazily and reopening Search preserves the
116
+ current query.
117
+ - ๐ŸŽจ **Themes and fonts.** Light, Dark, Docsify, Hopscotch. Reader,
118
+ Literary, Inter, Georgia, Baskerville, Sans, Mono.
119
+ - ๐Ÿงช **Tested.** 400 tests: unit coverage of the analytics engine, scene
120
+ parsing, save guards, history, and refresh behavior, plus end-to-end
121
+ tiers that boot the real server and drive the real UI in a browser.
122
+
123
+ ## ๐Ÿš€ Quick start
124
+
125
+ **Requirements:** Python 3.11+ on macOS or Linux. The server uses Unix-only
126
+ APIs (`fcntl`, and a real PTY for the terminal), so Windows needs WSL.
127
+
128
+ ```bash
129
+ git clone https://github.com/ourarash/proseview.git
130
+ cd proseview
131
+ pip install -r requirements.txt
132
+
133
+ # Run the dashboard against your novel repo
134
+ python -m proseview --root /path/to/your/novel
135
+ ```
136
+
137
+ A browser tab will open at `http://localhost:7842`. Press Ctrl-C to stop.
138
+
139
+ If you'd rather install proseview as a tool:
140
+
141
+ ```bash
142
+ pip install -e .
143
+ proseview --root /path/to/your/novel
144
+ ```
145
+
146
+ ## ๐Ÿ“ What proseview expects
147
+
148
+ A folder of Markdown scene files, one folder per chapter. The minimum
149
+ viable repo:
150
+
151
+ ```text
152
+ my-novel/
153
+ โ”œโ”€โ”€ manuscript/
154
+ โ”‚ โ”œโ”€โ”€ ch01/
155
+ โ”‚ โ”‚ โ”œโ”€โ”€ 01-opening.md
156
+ โ”‚ โ”‚ โ””โ”€โ”€ 02-meeting.md
157
+ โ”‚ โ””โ”€โ”€ ch02/
158
+ โ”‚ โ””โ”€โ”€ 01-aftermath.md
159
+ โ””โ”€โ”€ .proseview.yaml # optional
160
+ ```
161
+
162
+ Scene files use simple frontmatter:
163
+
164
+ ```markdown
165
+ ---
166
+ title: Opening
167
+ chapter: Chapter 1
168
+ status: draft
169
+ where: A bar in the West Village
170
+ when: Friday night, late
171
+ pov: Nima
172
+ characters: [Nima, Mira]
173
+ goal: Nima needs to get the question on the table
174
+ conflict: He's afraid she already has someone
175
+ outcome: She agrees to dinner; he leaves rattled
176
+ todos:
177
+ - Tighten the opening paragraph
178
+ ---
179
+
180
+ # Opening
181
+
182
+ The bar was loud and the music was bad...
183
+ ```
184
+
185
+ Every field is optional. Proseview reads what's there and falls back
186
+ gracefully on what isn't.
187
+
188
+ ### ๐Ÿ“ Frontmatter contract
189
+
190
+ These are the keys proseview recognizes. Any other keys are passed
191
+ through and ignored. Every field is optional.
192
+
193
+ #### Identity
194
+
195
+ - `title` (string) header of the scene viewer; defaults to a Title-Case
196
+ version of the filename stem.
197
+ - `chapter` (string) "Chapter" column in the scene table and the
198
+ chapter rows of charts; defaults to the chapter folder name.
199
+ - `status` (string) color-coded status badge. Conventional values:
200
+ `draft`, `revision`, `done`. Anything else renders as a generic chip;
201
+ missing means `unknown`.
202
+
203
+ #### Scene context
204
+
205
+ - `where` (string) "Where" row in the scene card. Also feeds the
206
+ **Setting Stickiness** chart (Words per Location).
207
+ - `location` (string) synonym for `where` (older convention).
208
+ - `when` (string) "When" row in the scene card. Free-form.
209
+ - `pov` (string) "POV" row in the scene card. Free-form.
210
+ - `characters` (list of strings) "Characters" row in the scene card;
211
+ each name is clickable to open the bio if
212
+ `<characters_path>/<name>.md` exists. Also feeds the **Character
213
+ Presence** and **Co-occurrence** charts.
214
+
215
+ #### Arc
216
+
217
+ - `goal` (string) "Goal" row in the arc panel.
218
+ - `conflict` (string) "Conflict" row in the arc panel.
219
+ - `outcome` (string) "Outcome" row in the arc panel.
220
+
221
+ #### Tasks
222
+
223
+ - `todos` (list of strings) each entry shows up as a frontmatter-level
224
+ TODO in the Tasks panel. Inline `<!-- TODO: ... -->` comments inside
225
+ the prose are picked up too and get a line anchor.
226
+
227
+ A scene with no frontmatter still renders, just with `Unknown` /
228
+ `Not defined` placeholders in the scene card and the file's stem as
229
+ its title.
230
+
231
+ ## โš™๏ธ Configuration
232
+
233
+ `proseview` works with zero config. Drop a `.proseview.yaml` at the
234
+ repo root if you want to customize:
235
+
236
+ ```yaml
237
+ # Where the manuscript lives. Default: manuscript/
238
+ manuscript_path: manuscript/
239
+
240
+ # Where character bios live. Default: story-bible/characters
241
+ characters_path: story-bible/characters
242
+
243
+ # Where AI skill prompts live. Default: skills
244
+ skills_path: skills
245
+
246
+ # Word-count goal for the finished book.
247
+ target_words: 80000
248
+
249
+ # Daily word goal (drives the "days to finish" estimate).
250
+ daily_target: 500
251
+
252
+ # Healthy band for local lexical variety (MATTR).
253
+ mattr_band: [0.74, 0.77]
254
+
255
+ # Healthy band for whole-scene lexical variety (MTLD).
256
+ mtld_band: [105, 130]
257
+
258
+ # Editor URL handler. One of: vscode, cursor, zed, positron, custom.
259
+ editor:
260
+ scheme: vscode
261
+
262
+ # Folders shown in the file tree alongside the manuscript.
263
+ repo_tab:
264
+ folders: [plans, continuity, outline, story-bible, docs, templates]
265
+ ```
266
+
267
+ Every key has a sensible default; missing folders are simply skipped.
268
+
269
+ ## ๐Ÿง  The analytics
270
+
271
+ Lexical health is real, not vibes:
272
+
273
+ - ๐Ÿ“ **MATTR** (moving-average type-token ratio, window 100). Measures
274
+ *local* vocabulary variety. Low = the same words inside a paragraph;
275
+ high = constant rotation that may feel jittery.
276
+ - ๐Ÿ“ **MTLD** (measure of textual lexical diversity). Measures
277
+ *whole-scene* variety. Low = the scene keeps circling the same ground;
278
+ high = the scene keeps reaching.
279
+ - ๐Ÿ“ **Sentence rhythm.** Per-chapter standard deviation of sentence
280
+ length. Static / Rhythmic / Dynamic zones are annotated on the chart.
281
+ - ๐Ÿ“ **Dialogue percentage**, **passive voice rate**, **crutch-word rate**,
282
+ **first-person density**, **sensory density**, **filter-verb rate**,
283
+ **paragraph length**.
284
+
285
+ Every scene gets a row in the deep-dive table; outliers get listed under
286
+ Editorial Alerts with a one-line revision signal.
287
+
288
+ ## ๐Ÿค Working with AI
289
+
290
+ Four places where AI shows up, all opt-in:
291
+
292
+ 1. **Selection menu.** Highlight any text in a scene. The pill that
293
+ appears includes `Add TODO`, `Add Note`, and (if the corresponding
294
+ tools are installed locally) `Run in Codex` and `Skills`. Skills are
295
+ reusable prompts you keep in `skills/<name>/SKILL.md`; they show up
296
+ automatically in the menu.
297
+ 2. **Agent menu.** From the scene header, launch a conversation with
298
+ Codex, Claude, or Gemini scoped to that file. The conversation runs
299
+ in the in-browser terminal so you can keep reading the prose
300
+ underneath while the agent works.
301
+ 3. **Discuss.** Choose `Discuss` in a scene or text-file header for a
302
+ document-aware conversation in the side dock. The document you are
303
+ reading is attached to each question by default โ€” drop its chip to omit
304
+ it, or press `@` to attach other files and folders. Tool and file
305
+ actions wait on approvals you can see.
306
+
307
+ Under the hood it starts a local `codex app-server` on demand and uses
308
+ your existing Codex login, model, and history. Proseview stores a bounded
309
+ list of thread IDs and display metadata for each document in your state
310
+ directory, and discards raw reasoning โ€” only Codex's own progress summaries
311
+ reach the browser. `History` lets you reopen, rename, export, or remove a
312
+ previous conversation. `New conversation` starts a blank discussion while
313
+ keeping the previous one available there.
314
+ 4. **TODOs as Markdown.** Every TODO and Note is a plain
315
+ `<!-- TODO: ... -->` or `<!-- NOTE[tag]: ... -->` comment in the
316
+ scene file. Your AI assistant can see them through the file, your
317
+ repo can track them through git, and you can grep them.
318
+
319
+ ## ๐Ÿ›ฃ๏ธ Roadmap
320
+
321
+ This is alpha. Things that are working and things that are coming:
322
+
323
+ - โœ… Live server, live reload, ProseMirror editor, highlights, TODOs,
324
+ notes, deep links, in-browser terminal, agent menu, and document-aware
325
+ Discuss conversations with Codex.
326
+ - โœ… Vendored front-end dependencies. chart.js, marked, xterm and
327
+ friends ship with the package and load from `/vendor/`. ProseMirror
328
+ modules are pinned to specific versions on esm.sh.
329
+ - โœ… Modularized front-end. The JS lives in twelve topical files under
330
+ `templates/assets/js/`, concatenated at render time.
331
+ - โœ… `proseview init` writes a starter `.proseview.yaml` so a fresh
332
+ novel repo gets a working configuration with one command.
333
+ - โœ… Persisted UI prefs. Your highlight-pass toggles and theme choices
334
+ survive scene navigation and reloads.
335
+ - ๐Ÿšง Diff-confirm for AI-suggested edits (selection runs in a terminal
336
+ today; nothing applies edits without your approval, but the diff UX
337
+ is still terminal-only).
338
+ - ๐Ÿšง Configurable agent list (Codex / Claude / Gemini are presets today).
339
+ - ๐Ÿšง Continuity surfacing (warn when a scene contradicts a known fact).
340
+ - ๐Ÿšง Frontmatter editor (status, where, todos) inside the scene viewer
341
+ so you don't need to drop into your text editor for routine fields.
342
+
343
+ See [plans/roadmap.md](plans/roadmap.md) for the full punch list.
344
+
345
+ ## ๐Ÿงช Development
346
+
347
+ ```bash
348
+ pip install -e ".[dev]"
349
+ pytest
350
+ ```
351
+
352
+ That runs the unit suite plus an HTTP end-to-end tier that boots a real
353
+ `proseview` subprocess and drives every endpoint โ€” saves and the conflict
354
+ guard, TODOs and notes, the AI proposal bridge through the actual CLI, live
355
+ reload over SSE, and PTY terminals โ€” asserting on bytes written to disk.
356
+ Discuss integration tests use a deterministic fake app-server and isolated
357
+ home/state directories; they never contact Codex, the network, or your profile.
358
+ ~15 seconds, no extra dependencies.
359
+
360
+ A browser tier drives the real UI in Chromium (editor round-trip fidelity,
361
+ the selection menu, highlight passes, deep links, agents, terminals, Discuss
362
+ streaming/approvals/shared-dock behavior, and applying an AI proposal end to
363
+ end). It's opt-in:
364
+
365
+ ```bash
366
+ pip install -e ".[e2e]"
367
+ python -m playwright install chromium
368
+ pytest -m e2e_browser
369
+ ```
370
+
371
+ Both tiers work on a throwaway copy of `fixtures/demo-repo`. See
372
+ [CONTRIBUTING.md](CONTRIBUTING.md) for details.
373
+
374
+ ## ๐Ÿ“œ License
375
+
376
+ MIT. See [LICENSE](LICENSE).