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.
- triage_dashboard-0.3.0/LICENSE +21 -0
- triage_dashboard-0.3.0/PKG-INFO +19 -0
- triage_dashboard-0.3.0/README.md +304 -0
- triage_dashboard-0.3.0/pyproject.toml +39 -0
- triage_dashboard-0.3.0/setup.cfg +4 -0
- triage_dashboard-0.3.0/src/triage_dashboard/__init__.py +0 -0
- triage_dashboard-0.3.0/src/triage_dashboard/__main__.py +47 -0
- triage_dashboard-0.3.0/src/triage_dashboard/app.py +848 -0
- triage_dashboard-0.3.0/src/triage_dashboard/applier.py +113 -0
- triage_dashboard-0.3.0/src/triage_dashboard/backend.py +96 -0
- triage_dashboard-0.3.0/src/triage_dashboard/claude_queue.py +467 -0
- triage_dashboard-0.3.0/src/triage_dashboard/data.py +1014 -0
- triage_dashboard-0.3.0/src/triage_dashboard/descriptions.py +183 -0
- triage_dashboard-0.3.0/src/triage_dashboard/reply_mode.py +61 -0
- triage_dashboard-0.3.0/src/triage_dashboard/static/favicon.svg +6 -0
- triage_dashboard-0.3.0/src/triage_dashboard/static/style.css +2193 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_applied_diff.html +51 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_button.html +31 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_status.html +10 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_toggle.html +7 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_apply_wrap.html +11 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_bug_report.html +144 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_content.html +22 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_draft_mutation.html +7 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_investigation_content.html +12 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_investigation_findings.html +66 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_investigation_overlay.html +23 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_level_select.html +13 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_owner_toggles.html +33 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_plan.html +36 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_queue_dropdown.html +68 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/_workspace.html +44 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/base.html +328 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/card.html +87 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/index.html +69 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/investigation.html +22 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/rail.html +70 -0
- triage_dashboard-0.3.0/src/triage_dashboard/templates/watching.html +61 -0
- triage_dashboard-0.3.0/src/triage_dashboard/watch.py +252 -0
- triage_dashboard-0.3.0/src/triage_dashboard.egg-info/PKG-INFO +19 -0
- triage_dashboard-0.3.0/src/triage_dashboard.egg-info/SOURCES.txt +43 -0
- triage_dashboard-0.3.0/src/triage_dashboard.egg-info/dependency_links.txt +1 -0
- triage_dashboard-0.3.0/src/triage_dashboard.egg-info/entry_points.txt +2 -0
- triage_dashboard-0.3.0/src/triage_dashboard.egg-info/requires.txt +12 -0
- 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/*"]
|
|
File without changes
|
|
@@ -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()
|