triage-dashboard 0.3.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 (45) hide show
  1. triage_dashboard-0.3.0/LICENSE +21 -0
  2. triage_dashboard-0.3.0/PKG-INFO +19 -0
  3. triage_dashboard-0.3.0/README.md +304 -0
  4. triage_dashboard-0.3.0/pyproject.toml +39 -0
  5. triage_dashboard-0.3.0/setup.cfg +4 -0
  6. triage_dashboard-0.3.0/src/triage_dashboard/__init__.py +0 -0
  7. triage_dashboard-0.3.0/src/triage_dashboard/__main__.py +47 -0
  8. triage_dashboard-0.3.0/src/triage_dashboard/app.py +848 -0
  9. triage_dashboard-0.3.0/src/triage_dashboard/applier.py +113 -0
  10. triage_dashboard-0.3.0/src/triage_dashboard/backend.py +96 -0
  11. triage_dashboard-0.3.0/src/triage_dashboard/claude_queue.py +467 -0
  12. triage_dashboard-0.3.0/src/triage_dashboard/data.py +1014 -0
  13. triage_dashboard-0.3.0/src/triage_dashboard/descriptions.py +183 -0
  14. triage_dashboard-0.3.0/src/triage_dashboard/reply_mode.py +61 -0
  15. triage_dashboard-0.3.0/src/triage_dashboard/static/favicon.svg +6 -0
  16. triage_dashboard-0.3.0/src/triage_dashboard/static/style.css +2193 -0
  17. triage_dashboard-0.3.0/src/triage_dashboard/templates/_applied_diff.html +51 -0
  18. triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_button.html +31 -0
  19. triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_status.html +10 -0
  20. triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_toggle.html +7 -0
  21. triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_wrap.html +11 -0
  22. triage_dashboard-0.3.0/src/triage_dashboard/templates/_bug_report.html +144 -0
  23. triage_dashboard-0.3.0/src/triage_dashboard/templates/_content.html +22 -0
  24. triage_dashboard-0.3.0/src/triage_dashboard/templates/_draft_mutation.html +7 -0
  25. triage_dashboard-0.3.0/src/triage_dashboard/templates/_investigation_content.html +12 -0
  26. triage_dashboard-0.3.0/src/triage_dashboard/templates/_investigation_findings.html +66 -0
  27. triage_dashboard-0.3.0/src/triage_dashboard/templates/_investigation_overlay.html +23 -0
  28. triage_dashboard-0.3.0/src/triage_dashboard/templates/_level_select.html +13 -0
  29. triage_dashboard-0.3.0/src/triage_dashboard/templates/_owner_toggles.html +33 -0
  30. triage_dashboard-0.3.0/src/triage_dashboard/templates/_plan.html +36 -0
  31. triage_dashboard-0.3.0/src/triage_dashboard/templates/_queue_dropdown.html +68 -0
  32. triage_dashboard-0.3.0/src/triage_dashboard/templates/_workspace.html +44 -0
  33. triage_dashboard-0.3.0/src/triage_dashboard/templates/base.html +328 -0
  34. triage_dashboard-0.3.0/src/triage_dashboard/templates/card.html +87 -0
  35. triage_dashboard-0.3.0/src/triage_dashboard/templates/index.html +69 -0
  36. triage_dashboard-0.3.0/src/triage_dashboard/templates/investigation.html +22 -0
  37. triage_dashboard-0.3.0/src/triage_dashboard/templates/rail.html +70 -0
  38. triage_dashboard-0.3.0/src/triage_dashboard/templates/watching.html +61 -0
  39. triage_dashboard-0.3.0/src/triage_dashboard/watch.py +252 -0
  40. triage_dashboard-0.3.0/src/triage_dashboard.egg-info/PKG-INFO +19 -0
  41. triage_dashboard-0.3.0/src/triage_dashboard.egg-info/SOURCES.txt +43 -0
  42. triage_dashboard-0.3.0/src/triage_dashboard.egg-info/dependency_links.txt +1 -0
  43. triage_dashboard-0.3.0/src/triage_dashboard.egg-info/entry_points.txt +2 -0
  44. triage_dashboard-0.3.0/src/triage_dashboard.egg-info/requires.txt +12 -0
  45. triage_dashboard-0.3.0/src/triage_dashboard.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alastor Wu
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 all
13
+ 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,19 @@
1
+ Metadata-Version: 2.4
2
+ Name: triage-dashboard
3
+ Version: 0.3.0
4
+ Summary: Local web dashboard for Firefox A/V bug triage. Consumes /triage skill output from ~/firefox-triage/.
5
+ License: MIT
6
+ Requires-Python: >=3.11
7
+ License-File: LICENSE
8
+ Requires-Dist: fastapi>=0.110
9
+ Requires-Dist: uvicorn[standard]>=0.27
10
+ Requires-Dist: jinja2>=3.1
11
+ Requires-Dist: python-multipart>=0.0.9
12
+ Requires-Dist: markdown>=3.5
13
+ Requires-Dist: bleach>=6.0
14
+ Requires-Dist: watchdog>=4.0
15
+ Requires-Dist: pyyaml>=6.0
16
+ Provides-Extra: dev
17
+ Requires-Dist: pytest>=8; extra == "dev"
18
+ Requires-Dist: httpx>=0.27; extra == "dev"
19
+ Dynamic: license-file
@@ -0,0 +1,304 @@
1
+ # Firefox Triage Dashboard
2
+
3
+ A local web dashboard that turns Firefox A/V bug triage into a focused
4
+ review-and-approve flow. You run `/triage` in a Claude session, the
5
+ dashboard surfaces each draft as a card, you review with full
6
+ investigation context, then approve each Bugzilla action one at a time.
7
+
8
+ The dashboard is the *cockpit* — it doesn't make decisions on its own.
9
+ Every Bugzilla write is gated behind your approval and a final
10
+ `bugzilla-cli apply` confirmation at the terminal. Nothing posts to
11
+ Bugzilla automatically.
12
+
13
+ ### Read-only vs reply mode
14
+
15
+ The dashboard detects whether a Bugzilla **API key** is configured — the same
16
+ signal `bugzilla-cli` uses (`$BUGZILLA_BOT_API_KEY`, or
17
+ `~/.config/triage/secrets`):
18
+
19
+ - **Reply mode** (key present) — full flow: Apply / skip per card and the
20
+ Process-queue drain that writes via `bugzilla-cli apply`.
21
+ - **Read-only** (no key) — the dashboard shows a **"read-only · drafts only"**
22
+ badge and drops every write affordance: each card's Apply becomes a disabled
23
+ **Read-only** pill, the owner **CC me / NI me / Assign me** toggles are hidden,
24
+ the will-apply diff is non-editable and omits the cc / ni / assign rows, and the
25
+ Process-queue drain prompt is told to **skip the apply (write) step**. You still
26
+ see the full AI draft — analysis, proposed comment, and the proposed
27
+ severity/priority/resolution — just nothing that writes back. Detection is live:
28
+ configure a key (`bugzilla-cli setup`) and reload to switch to reply mode.
29
+
30
+ ---
31
+
32
+ ## The triage loop, end to end
33
+
34
+ Three actors share the work: **`/triage`** analyzes bugs and writes
35
+ drafts (read-only on Bugzilla), the **dashboard** is where you review and
36
+ decide, and the **Process queue** drain is the *only* thing that writes to
37
+ Bugzilla — and only after a per-bug approval.
38
+
39
+ ```
40
+ ┌──────────────────────────────────────────────────────────┐
41
+ │ /triage (full) READ-ONLY on Bugzilla │
42
+ │ ─────────────────────────────────────────────────────── │
43
+ │ 1. watch-poll → replies on NI'd bugs │
44
+ │ (replied / ni_cleared / stale / auto_removed / …) │
45
+ │ 2. fetch new bugs (last 14 days) │
46
+ │ 3. analyze each (parallel sub-agents; │
47
+ │ /bug-start investigation for §1b) │
48
+ └───────────────────────────┬──────────────────────────────┘
49
+ │ writes (local files only)
50
+
51
+ pending/bug-<id>.json + ni-watch.json + investigation .md
52
+
53
+
54
+ ┌──────────────────────────────────────────────────────────┐
55
+ │ DASHBOARD reads those files; never writes BMO│
56
+ │ tabs: Analyzed · Needs Info · Close/Reassign · Awaiting │
57
+ │ you review each draft → │
58
+ └────┬───────────────────┬───────────────────┬─────────────┘
59
+ │ Revise │ Apply (toggle) │ Skip
60
+ ▼ ▼ ▼
61
+ queue: refine queue: apply delete draft
62
+ (+feedback) │ (no queue)
63
+ └───────────────────┴──── append → claude-queue.jsonl
64
+
65
+
66
+ ┌──────────────────────────────────────────────────────────┐
67
+ │ PROCESS QUEUE (drain prompt) — partitions by action │
68
+ │ ─────────────────────────────────────────────────────── │
69
+ │ refine → /triage-apply-feedback │
70
+ │ (re-draft JSON + capture wiki lesson) │
71
+ │ apply → AskUserQuestion per bug (yes / no) │
72
+ │ └─ yes → bugzilla-cli apply ◄── ONLY │
73
+ │ • posts comment/NI/fields to BMO │
74
+ │ • archives draft → applied/ │
75
+ │ • adds bug to ni-watch │
76
+ │ bug-start → /bug-start │
77
+ └───────────────────────────┬──────────────────────────────┘
78
+ │ applied bug
79
+
80
+ Awaiting reply tab ◄── folded report (applied/ + investigation),
81
+ │ no AI draft comment
82
+ │ reporter answers the NI on Bugzilla
83
+
84
+ next /triage → watch-poll sees the reply ──────┐
85
+
86
+ ◄────────────────────────────────────────────────┘ loop
87
+ ```
88
+
89
+ **Second round?** Just run full `/triage` again (no arguments). One run
90
+ both re-polls the NI watch list for replies (`watch-poll`) and fetches
91
+ any new bugs from the last 14 days. `/triage <id>` single-bug mode skips
92
+ *both*, so use bare `/triage` to close the loop.
93
+
94
+ ---
95
+
96
+ ## What each tab means
97
+
98
+ The topbar has four tabs. Each one represents a decision class — a
99
+ draft sits in exactly one of them, based on what's in its pending JSON.
100
+
101
+ ### Analyzed (§1b)
102
+
103
+ These are bugs you've **triaged**: severity + priority set, root cause
104
+ identifiable from the available data (media-preset profile, media log
105
+ with NS_ERROR / decoder signal, crash ID with media stack frame, or
106
+ reporter-cited source code). The draft includes:
107
+
108
+ - A public comment summarizing findings
109
+ - Severity + priority
110
+ - Optional meta-bug blocker (e.g. autoplay, YouTube playback)
111
+ - A needinfo on the triage owner so the bug enters their queue
112
+
113
+ **Apply does:** posts the comment, sets S/P, adds blocks/CC, sends the
114
+ NI — all bundled into one atomic `bugzilla-cli apply` call.
115
+
116
+ Each Analyzed card carries a **Findings** block surfacing the
117
+ `/bug-start` investigation: root cause, affected files (linked to
118
+ searchfox at the specific lines cited), regression range, related
119
+ bugs, complexity. The investigation runs in shallow ("triage") mode
120
+ during `/triage` so the dashboard has data to show without making
121
+ `/triage` take an hour. Re-run `/bug-start <bug_id>` (no flag) in
122
+ deep mode when you're ready to implement.
123
+
124
+ ### Needs Info (§1a)
125
+
126
+ The bug doesn't yet have enough data for triage. The draft asks the
127
+ reporter (or sometimes a Mozilla engineer) for the specific missing
128
+ pieces — `about:support`, a media-preset profile, a clean-profile
129
+ test, a media log with the `media` preset enabled, etc.
130
+
131
+ **Apply does:** posts the question + sets the needinfo flag on the
132
+ reporter. Adds the bug to a local watch list so we notice when the
133
+ reporter replies.
134
+
135
+ ### Close / Reassign (§1c)
136
+
137
+ The bug shouldn't live in A/V triage queue any longer:
138
+
139
+ - **Duplicate** of another bug — resolve as DUPLICATE, link the original
140
+ - **Invalid** — works as intended, post the rationale
141
+ - **Incomplete** — reporter stalled, no path forward
142
+ - **Wrong component** — reassign to the team that actually owns it
143
+ - **Stalled** — add the `stalled` keyword, leave open
144
+
145
+ **Apply does:** sets the resolution (or reassigns product/component)
146
+ and posts the explanatory comment.
147
+
148
+ ### Awaiting reply
149
+
150
+ Bugs we've already needinfo'd, waiting on a response. This tab is
151
+ read-only — there's no Apply action because we're not the actors
152
+ right now. A `stalled` indicator surfaces when the NI is more than
153
+ 14 days old, so we know which ones need a follow-up or an
154
+ INCOMPLETE resolution.
155
+
156
+ Each entry keeps the bug's full context from when it was applied —
157
+ component and current S/P in the collapsed row, and a folded **Details**
158
+ disclosure with the report (platform, reporter, `ai_reasoning`), the
159
+ applied changes, and any investigation findings. The AI draft comment is
160
+ the only thing dropped. The detail is restored from the archived draft
161
+ (`~/firefox-triage/applied/bug-<id>.json`, written by `bugzilla-cli
162
+ apply`) plus the investigation file.
163
+
164
+ ---
165
+
166
+ ## How we investigate bugs
167
+
168
+ The dashboard doesn't investigate code itself — that's `/bug-start`'s
169
+ job. The two skills work together via the dashboard:
170
+
171
+ - **`/triage`** classifies each bug. For Analyzed bugs, it dispatches a
172
+ shallow `/bug-start --triage-mode` subagent in parallel with the
173
+ others (parallel cap of 4 at a time, so total wall-clock is bounded).
174
+
175
+ - **`/bug-start --triage-mode`** produces a shallow but useful
176
+ investigation file: root cause hypothesis or verification, affected
177
+ files (with line citations where the body cites them), regression
178
+ range if found, related bugs, complexity estimate. It does *not*
179
+ produce an implementation plan, patch arrangement, or test plan —
180
+ that's deep mode's job, run later when you're ready to write code.
181
+
182
+ - **`/bug-start` (no flag)** runs deep mode and produces the full
183
+ investigation document. You invoke this manually when you're about
184
+ to fix the bug.
185
+
186
+ Investigation files live in `$FX_BUG_INVESTIGATION_DIR` (default
187
+ `~/.fx-bug-toolkit/bug-investigation/`, shared with the fx-bug-toolkit
188
+ plugin that writes them) as `bug-<id>-investigation.md`. The dashboard
189
+ serves them itself at `/investigation/<id>`, so the "Open full
190
+ investigation →" link is always valid and nothing has to leave your
191
+ machine (no remote repo required).
192
+
193
+ If the bug doesn't have enough data for `/bug-start` to be useful (no
194
+ media profile, no media log, no crash signature, etc.), the skill
195
+ classifies it Needs Info instead and asks the reporter for the
196
+ missing piece — no investigation runs.
197
+
198
+ ---
199
+
200
+ ## Key signals on a card
201
+
202
+ While reading a card, watch for these:
203
+
204
+ - **Rail tags** (small pills on each rail item):
205
+ - `emergency` — bug has `sec-critical`, `sec-high`, or `topcrash`
206
+ keyword. Look at this first.
207
+ - `regression` — bug has the `regression` keyword. Backout candidate
208
+ or land-day fast-track.
209
+ - `stalled` (Awaiting reply tab only) — NI sent >14 days ago.
210
+
211
+ - **Findings block** on Analyzed cards — investigation results.
212
+ - Status pill: `investigated` (done) / `investigating` (mid-run) /
213
+ `investigation-stalled` (lock file >30 min old, /bug-start may
214
+ have crashed)
215
+ - "shallow · re-run for deep" badge when the investigation was
216
+ triage-mode only
217
+
218
+ - **Card-head S/P pills** show the bug's *current* Bugzilla state —
219
+ not what the draft will set. The "Will apply" footer at the bottom
220
+ shows the draft's deltas. In that footer the **severity / priority
221
+ are editable dropdowns**: they default to the AI's proposed level,
222
+ and selecting a different one overrides what will actually be applied
223
+ this round.
224
+
225
+ - **Pending feedback** — refines you've queued for this specific bug
226
+ via the composer. ✕ on any row to remove it before draining.
227
+
228
+ ---
229
+
230
+ ## Drain queue
231
+
232
+ Actions queue to `~/firefox-triage/claude-queue.jsonl`:
233
+
234
+ - **Refines** — when you click "Revise draft" with feedback, the next
235
+ Claude session re-drafts that bug via `/triage-apply-feedback`
236
+ - **Apply** — clicking Apply queues a single `apply` action and the
237
+ button flips to **Applied**; clicking Applied again removes it (the
238
+ toggle is reversible). `/bug-start` is **not** chained onto Apply — it
239
+ already runs during `/triage` for Analyzed bugs.
240
+
241
+ The topbar dropdown shows everything queued. Clicking "Copy prompt"
242
+ copies a short instruction set that you paste into a Claude session,
243
+ which then reads the JSONL and processes each entry. For every queued
244
+ apply, the drain asks you **per bug** (a yes/no question) before posting;
245
+ on yes it runs `bugzilla-cli apply <id>` with your approval. That per-bug
246
+ confirmation is the safety gate — no Bugzilla write happens without it.
247
+
248
+ You can remove queued items individually (✕ in the dropdown) without
249
+ draining the whole queue.
250
+
251
+ ---
252
+
253
+ ## Running it locally
254
+
255
+ ```bash
256
+ # One-time
257
+ git clone https://github.com/alastor0325/firefox-triage-dashboard.git
258
+ cd firefox-triage-dashboard
259
+ python3 -m venv .venv
260
+ .venv/bin/pip install -e .
261
+
262
+ # Each session — foreground (blocks the terminal, opens a browser)
263
+ .venv/bin/triage-dashboard # opens http://127.0.0.1:8765
264
+
265
+ # Or run it in the background with the control script
266
+ scripts/serve.sh start # launch (no browser pop), health-checked
267
+ scripts/serve.sh status # is it up? PID + HTTP check
268
+ scripts/serve.sh restart # stop + start
269
+ scripts/serve.sh logs # tail the server log
270
+ scripts/serve.sh stop # stop it
271
+ # env overrides: HOST=0.0.0.0 PORT=9000 scripts/serve.sh start
272
+ ```
273
+
274
+ The dashboard reads triage data from `~/firefox-triage/` by default (or
275
+ `$TRIAGE_DIR`), and investigations from `$FX_BUG_INVESTIGATION_DIR`
276
+ (default `~/.fx-bug-toolkit/bug-investigation/` — the same variable and
277
+ default the fx-bug-toolkit plugin uses, so both see the same files).
278
+ Pending drafts live in `~/firefox-triage/pending/`. These directories are
279
+ created by the `/triage` and `/bug-start` skills, not by the dashboard.
280
+
281
+ The dashboard ships with a mock Bugzilla backend by default —
282
+ clicking Apply shows what *would* happen but doesn't actually post.
283
+ Real writes go through `bugzilla-cli apply` in a separate Claude
284
+ terminal, gated by its `[y/N]` confirmation.
285
+
286
+ ---
287
+
288
+ ## Related projects
289
+
290
+ - **[fx-bug-toolkit](https://github.com/alastor0325/fx-bug-toolkit)** — the Claude Code plugin behind the workflow: `/bug-start` writes the investigation files this dashboard reads (from `$FX_BUG_INVESTIGATION_DIR`), and the `/triage` skills are being folded in there too
291
+ - **[bugzilla-cli](https://github.com/alastor0325/bugzilla-cli)** — the underlying tool for Bugzilla I/O, including the `[y/N]` apply prompt
292
+
293
+ ---
294
+
295
+ ## Why this exists
296
+
297
+ A/V triage involves a lot of context per bug: the bug's description,
298
+ artifacts (profiles, logs, crashes), prior triage history, related
299
+ bugs, and increasingly, AI-generated analysis. Doing this in
300
+ Bugzilla's web UI means flipping between many tabs per bug. The
301
+ dashboard consolidates all of it into one card per bug, surfaces the
302
+ investigation findings inline, and keeps the human-in-the-loop
303
+ guarantee firmly at the `bugzilla-cli apply` boundary — so the speedup
304
+ comes from better tooling, not from skipping review.
@@ -0,0 +1,39 @@
1
+ [project]
2
+ name = "triage-dashboard"
3
+ version = "0.3.0"
4
+ description = "Local web dashboard for Firefox A/V bug triage. Consumes /triage skill output from ~/firefox-triage/."
5
+ license = { text = "MIT" }
6
+ requires-python = ">=3.11"
7
+ dependencies = [
8
+ "fastapi>=0.110",
9
+ "uvicorn[standard]>=0.27",
10
+ "jinja2>=3.1",
11
+ "python-multipart>=0.0.9",
12
+ "markdown>=3.5",
13
+ "bleach>=6.0",
14
+ "watchdog>=4.0",
15
+ "pyyaml>=6.0",
16
+ ]
17
+
18
+ [project.optional-dependencies]
19
+ dev = [
20
+ "pytest>=8",
21
+ "httpx>=0.27",
22
+ ]
23
+
24
+ [project.scripts]
25
+ triage-dashboard = "triage_dashboard.__main__:main"
26
+
27
+ [tool.pytest.ini_options]
28
+ testpaths = ["tests"]
29
+ addopts = "-q"
30
+
31
+ [build-system]
32
+ requires = ["setuptools>=68"]
33
+ build-backend = "setuptools.build_meta"
34
+
35
+ [tool.setuptools.packages.find]
36
+ where = ["src"]
37
+
38
+ [tool.setuptools.package-data]
39
+ triage_dashboard = ["templates/*.html", "static/*"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,47 @@
1
+ """CLI entry: `triage-dashboard` runs the server and opens the browser."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import argparse
6
+ import threading
7
+ import time
8
+ import webbrowser
9
+
10
+ import uvicorn
11
+
12
+
13
+ def main() -> None:
14
+ parser = argparse.ArgumentParser(prog="triage-dashboard")
15
+ parser.add_argument("--host", default="127.0.0.1")
16
+ parser.add_argument("--port", type=int, default=8765)
17
+ parser.add_argument(
18
+ "--no-browser",
19
+ action="store_true",
20
+ help="Don't auto-open the browser.",
21
+ )
22
+ parser.add_argument(
23
+ "--reload",
24
+ action="store_true",
25
+ help="Restart on file change (dev mode).",
26
+ )
27
+ args = parser.parse_args()
28
+
29
+ url = f"http://{args.host}:{args.port}/"
30
+ if not args.no_browser:
31
+ # Open in a delayed thread so the server has a chance to bind.
32
+ threading.Thread(
33
+ target=lambda: (time.sleep(0.6), webbrowser.open(url)),
34
+ daemon=True,
35
+ ).start()
36
+
37
+ uvicorn.run(
38
+ "triage_dashboard.app:app",
39
+ host=args.host,
40
+ port=args.port,
41
+ reload=args.reload,
42
+ log_level="info",
43
+ )
44
+
45
+
46
+ if __name__ == "__main__":
47
+ main()