@polishd/next 0.2.2 → 0.2.3-dev.1

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 (150) hide show
  1. package/AGENTS.md +2 -1
  2. package/CHANGELOG.md +238 -0
  3. package/README.md +63 -0
  4. package/bin/doctor.mjs +8 -1
  5. package/dist/ai/digest.d.ts.map +1 -1
  6. package/dist/ai/digest.js +3 -2
  7. package/dist/ai/digest.js.map +1 -1
  8. package/dist/ai/github.d.ts +22 -1
  9. package/dist/ai/github.d.ts.map +1 -1
  10. package/dist/ai/github.js +99 -3
  11. package/dist/ai/github.js.map +1 -1
  12. package/dist/ai/issue-pages.d.ts +52 -0
  13. package/dist/ai/issue-pages.d.ts.map +1 -0
  14. package/dist/ai/issue-pages.js +50 -0
  15. package/dist/ai/issue-pages.js.map +1 -0
  16. package/dist/ai/issues.d.ts +13 -1
  17. package/dist/ai/issues.d.ts.map +1 -1
  18. package/dist/ai/issues.js +60 -4
  19. package/dist/ai/issues.js.map +1 -1
  20. package/dist/ai/summary.d.ts.map +1 -1
  21. package/dist/ai/summary.js +7 -0
  22. package/dist/ai/summary.js.map +1 -1
  23. package/dist/ai/types.d.ts +43 -0
  24. package/dist/ai/types.d.ts.map +1 -1
  25. package/dist/client/dom.d.ts +23 -0
  26. package/dist/client/dom.d.ts.map +1 -1
  27. package/dist/client/dom.js +45 -2
  28. package/dist/client/dom.js.map +1 -1
  29. package/dist/client/init.d.ts.map +1 -1
  30. package/dist/client/init.js +54 -14
  31. package/dist/client/init.js.map +1 -1
  32. package/dist/client/monitor.d.ts.map +1 -1
  33. package/dist/client/monitor.js +5 -1
  34. package/dist/client/monitor.js.map +1 -1
  35. package/dist/client/script-provenance.d.ts +21 -0
  36. package/dist/client/script-provenance.d.ts.map +1 -0
  37. package/dist/client/script-provenance.js +127 -0
  38. package/dist/client/script-provenance.js.map +1 -0
  39. package/dist/config.d.ts +10 -0
  40. package/dist/config.d.ts.map +1 -1
  41. package/dist/config.js +1 -0
  42. package/dist/config.js.map +1 -1
  43. package/dist/dashboard/chrome.d.ts +4 -2
  44. package/dist/dashboard/chrome.d.ts.map +1 -1
  45. package/dist/dashboard/chrome.js +15 -5
  46. package/dist/dashboard/chrome.js.map +1 -1
  47. package/dist/dashboard/design-review-card.d.ts.map +1 -1
  48. package/dist/dashboard/design-review-card.js +3 -3
  49. package/dist/dashboard/design-review-card.js.map +1 -1
  50. package/dist/dashboard/design.d.ts +5 -1
  51. package/dist/dashboard/design.d.ts.map +1 -1
  52. package/dist/dashboard/design.js +3 -2
  53. package/dist/dashboard/design.js.map +1 -1
  54. package/dist/dashboard/drawer.d.ts +34 -0
  55. package/dist/dashboard/drawer.d.ts.map +1 -0
  56. package/dist/dashboard/drawer.js +44 -0
  57. package/dist/dashboard/drawer.js.map +1 -0
  58. package/dist/dashboard/index.d.ts +3 -1
  59. package/dist/dashboard/index.d.ts.map +1 -1
  60. package/dist/dashboard/index.js +48 -37
  61. package/dist/dashboard/index.js.map +1 -1
  62. package/dist/dashboard/installs.d.ts.map +1 -1
  63. package/dist/dashboard/installs.js +2 -1
  64. package/dist/dashboard/installs.js.map +1 -1
  65. package/dist/dashboard/issues.d.ts +9 -0
  66. package/dist/dashboard/issues.d.ts.map +1 -0
  67. package/dist/dashboard/issues.js +81 -0
  68. package/dist/dashboard/issues.js.map +1 -0
  69. package/dist/dashboard/journeys.d.ts.map +1 -1
  70. package/dist/dashboard/journeys.js +4 -2
  71. package/dist/dashboard/journeys.js.map +1 -1
  72. package/dist/dashboard/metric-trends.d.ts +6 -0
  73. package/dist/dashboard/metric-trends.d.ts.map +1 -0
  74. package/dist/dashboard/metric-trends.js +236 -0
  75. package/dist/dashboard/metric-trends.js.map +1 -0
  76. package/dist/dashboard/pages.d.ts.map +1 -1
  77. package/dist/dashboard/pages.js +8 -46
  78. package/dist/dashboard/pages.js.map +1 -1
  79. package/dist/dashboard/settings.d.ts.map +1 -1
  80. package/dist/dashboard/settings.js +6 -2
  81. package/dist/dashboard/settings.js.map +1 -1
  82. package/dist/dashboard/show-more.d.ts.map +1 -1
  83. package/dist/dashboard/show-more.js +1 -1
  84. package/dist/dashboard/show-more.js.map +1 -1
  85. package/dist/dashboard/snapshot-actions.d.ts +16 -0
  86. package/dist/dashboard/snapshot-actions.d.ts.map +1 -0
  87. package/dist/dashboard/snapshot-actions.js +79 -0
  88. package/dist/dashboard/snapshot-actions.js.map +1 -0
  89. package/dist/dashboard/snapshots.d.ts +13 -0
  90. package/dist/dashboard/snapshots.d.ts.map +1 -0
  91. package/dist/dashboard/snapshots.js +88 -0
  92. package/dist/dashboard/snapshots.js.map +1 -0
  93. package/dist/dashboard/summary.d.ts.map +1 -1
  94. package/dist/dashboard/summary.js +11 -6
  95. package/dist/dashboard/summary.js.map +1 -1
  96. package/dist/dashboard/telemetry.d.ts +3 -1
  97. package/dist/dashboard/telemetry.d.ts.map +1 -1
  98. package/dist/dashboard/telemetry.js +55 -12
  99. package/dist/dashboard/telemetry.js.map +1 -1
  100. package/dist/dashboard/ui.d.ts +33 -6
  101. package/dist/dashboard/ui.d.ts.map +1 -1
  102. package/dist/dashboard/ui.js +44 -6
  103. package/dist/dashboard/ui.js.map +1 -1
  104. package/dist/dashboard.css +193 -2
  105. package/dist/server/ingest.d.ts +2 -5
  106. package/dist/server/ingest.d.ts.map +1 -1
  107. package/dist/server/ingest.js +47 -10
  108. package/dist/server/ingest.js.map +1 -1
  109. package/dist/server/queries.d.ts +64 -11
  110. package/dist/server/queries.d.ts.map +1 -1
  111. package/dist/server/queries.js +207 -37
  112. package/dist/server/queries.js.map +1 -1
  113. package/dist/server/reclassify.d.ts +3 -0
  114. package/dist/server/reclassify.d.ts.map +1 -0
  115. package/dist/server/reclassify.js +65 -0
  116. package/dist/server/reclassify.js.map +1 -0
  117. package/dist/server/snapshots.d.ts +81 -0
  118. package/dist/server/snapshots.d.ts.map +1 -0
  119. package/dist/server/snapshots.js +371 -0
  120. package/dist/server/snapshots.js.map +1 -0
  121. package/dist/server/store.d.ts +5 -0
  122. package/dist/server/store.d.ts.map +1 -1
  123. package/dist/server/store.js +17 -0
  124. package/dist/server/store.js.map +1 -1
  125. package/dist/server/telemetry.d.ts +13 -0
  126. package/dist/server/telemetry.d.ts.map +1 -1
  127. package/dist/server/telemetry.js +28 -7
  128. package/dist/server/telemetry.js.map +1 -1
  129. package/dist/shared/capture-status.d.ts +99 -0
  130. package/dist/shared/capture-status.d.ts.map +1 -0
  131. package/dist/shared/capture-status.js +133 -0
  132. package/dist/shared/capture-status.js.map +1 -0
  133. package/dist/shared/error-noise.d.ts +39 -0
  134. package/dist/shared/error-noise.d.ts.map +1 -0
  135. package/dist/shared/error-noise.js +101 -0
  136. package/dist/shared/error-noise.js.map +1 -0
  137. package/dist/shared/metric-buckets.d.ts +31 -0
  138. package/dist/shared/metric-buckets.d.ts.map +1 -0
  139. package/dist/shared/metric-buckets.js +49 -0
  140. package/dist/shared/metric-buckets.js.map +1 -0
  141. package/dist/shared/text-signals.d.ts +56 -0
  142. package/dist/shared/text-signals.d.ts.map +1 -0
  143. package/dist/shared/text-signals.js +80 -0
  144. package/dist/shared/text-signals.js.map +1 -0
  145. package/dist/shared/types.d.ts +1 -1
  146. package/dist/shared/types.d.ts.map +1 -1
  147. package/dist/shared/types.js +4 -0
  148. package/dist/shared/types.js.map +1 -1
  149. package/docs/SETUP.md +25 -0
  150. package/package.json +9 -2
package/AGENTS.md CHANGED
@@ -325,6 +325,7 @@ survive there.
325
325
  | Variable | Required | Purpose |
326
326
  |---|---|---|
327
327
  | `POLISHD_DATABASE_URL` | for production capture | Pooled Postgres connection string |
328
+ | `BLOB_READ_WRITE_TOKEN` | for production site snapshots | Injected automatically when a Vercel Blob store is connected; snapshot images upload there instead of the (read-only) filesystem |
328
329
  | `POLISHD_DASHBOARD_TOKEN` | for production, unless auth is wired | Protects `/polishd`. `openssl rand -hex 32` |
329
330
  | `POLISHD_DASHBOARD_PUBLIC` | no | `true` to serve the dashboard unguarded on purpose |
330
331
  | `POLISHD_SESSION_COOKIE` | no | Rename the session cookie; read by both proxy and ingest |
@@ -348,7 +349,7 @@ Run `npx @polishd/next doctor` first — it names most of these directly.
348
349
  | Every `/api/*` route 404s | Proxy matcher matches `/api` | Restore the `api` exclusion in the matcher |
349
350
  | Dashboard renders unstyled | `@polishd/next/dashboard.css` not imported in the page | Phase 4 |
350
351
  | Dashboard is empty, warning about the store | No writable backend | Set `POLISHD_DATABASE_URL`, or check Node ≥ 22.5 in dev |
351
- | Dashboard shows *"no session cookie — your proxy isn't running"* | Proxy missing, misnamed for the Next major, matcher not covering the path, or a botched merge | Phase 3c and `doctor --url` |
352
+ | Dashboard shows *"no session cookie — your proxy isn't running"* | Proxy missing, misnamed for the Next major, matcher not covering the path, or a botched merge. Red means *nothing is being stored* — with events landing you get a neutral note instead | Phase 3c and `doctor --url <origin>`; plain `doctor` only reads the source tree, so it can pass while a deployed build still mints no cookie |
352
353
  | Beacons return 200 but nothing is stored | Same as above — ingest answers `{ok:true,stored:0,reason:"no_session"}` so the client cannot see a failure | `doctor --url http://localhost:3000` |
353
354
  | Proxy and ingest disagree on the cookie name | `sessionCookie` threaded into one layer but not another | Set `POLISHD_SESSION_COOKIE`; both read it |
354
355
  | `ERR_UNKNOWN_BUILTIN_MODULE: node:sqlite` | Node < 22.5 | Upgrade Node, or configure Postgres |
package/CHANGELOG.md CHANGED
@@ -1,5 +1,243 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ### Every Overview tile opens its own graph
6
+
7
+ The six numbers at the top of the Analytics tab were all-time totals, which
8
+ answer "how much" and never "when" — 37 rage clicks is a different problem if
9
+ they all landed on Tuesday. Each tile is now a button: clicking one opens a
10
+ bottom drawer with that metric bucketed over time.
11
+
12
+ - **Hourly or daily**, switchable in the drawer. Both series are computed on
13
+ the server and travel together, so flipping granularity — or switching
14
+ metric from inside the drawer — costs no round trip. Daily is the default
15
+ once there's more than a day of history; before that a daily chart is one
16
+ bar, and hourly is the only shape worth drawing.
17
+ - Every tile grows a **sparkline**, which is both the hint that there's a
18
+ chart behind the number and the shape of it at a glance.
19
+ - The window ends at the **newest bucket that has data**, not at now, so an
20
+ install last browsed three days ago still gets a chart instead of an empty
21
+ one. It covers the last 48 hours or 30 days of activity; where that differs
22
+ from the tile's all-time total, the drawer says so rather than leaving the
23
+ reader to notice.
24
+ - Quiet buckets are drawn as **measured zeros**, not skipped — an empty night
25
+ is a fact about the site, and dropping those points would silently compress
26
+ the axis.
27
+ - **Sessions are never summed.** A visitor active across three hours is
28
+ counted in all three buckets, so the drawer shows peak/average/latest for
29
+ that metric and explains why there's no total.
30
+ - Reading a bucket works by pointer, by tap, and by keyboard (←/→, Home/End
31
+ on the focused chart); the readout sits above the plot so it never covers
32
+ the tallest bar, which is the one you were reaching for.
33
+ - Buckets start at the UTC hour or day, matching the existing per-page chart.
34
+ A visitor whose clock is set to next year can't anchor the window there and
35
+ blank the chart — the windowing rule lives in
36
+ `src/shared/metric-buckets.ts`, pure and tested (`npm test`).
37
+
38
+ The bottom drawer itself, the info tooltip and the axis-tick maths are now
39
+ shared (`src/dashboard/drawer.tsx`, `src/dashboard/ui.tsx`) instead of copied
40
+ between the Top-pages table and this, which is what stopped the two charts
41
+ drifting apart.
42
+ ### An Issues tab: every bug polishd filed, in one list
43
+
44
+ Filed issues used to exist only inside the loss that produced them — one
45
+ summary, one card, gone at the next regenerate. The dashboard grows an
46
+ **Issues** tab that lists them all, newest first, and appears only once a
47
+ GitHub repository is connected (nothing to list, and no way to list it,
48
+ otherwise).
49
+
50
+ - Each row joins two sources. The analytics **evidence**, the claim as the
51
+ summary stated it, and the verdict the source verification reached are
52
+ polishd's own record; the title, state, labels, assignees, comment count and
53
+ body are read live from GitHub on every render, so a bug closed an hour ago
54
+ reads as closed here.
55
+ - The issue log the dedupe already kept is what makes the list *ours* rather
56
+ than the repo's — a repo full of other people's issues stays that way. New
57
+ filings additionally record the claim, the verdict and the filing time;
58
+ entries written by earlier versions have only a number and a URL and still
59
+ render, dated from GitHub's own `created_at`.
60
+ - An issue that can no longer be read — deleted, transferred, token access
61
+ revoked — keeps its row and says so, rather than quietly disappearing from
62
+ a count you were trusting.
63
+ - Loading the tab is **one GitHub API call**, not one per issue. The repo's
64
+ issue list returns whole issues, body and all, a hundred at a time, so a
65
+ single page answers for every issue polishd has ever filed. Issue numbers
66
+ only climb and the list comes back newest-first, so a page that has dropped
67
+ below the oldest number we want proves no later page can hold it, and paging
68
+ stops; anything buried past a three-page budget is read individually. The
69
+ rule lives in `src/ai/issue-pages.ts` — pure, no network — with tests
70
+ (`npm test`).
71
+
72
+ ### Site snapshots now work in production
73
+
74
+ Capturing a snapshot on a serverless host used to fail on two fronts at once:
75
+ no browser to launch and no writable filesystem to keep the images on. Both
76
+ are now handled, and neither needs configuration beyond connecting a Vercel
77
+ Blob store to the project:
78
+
79
+ - When `BLOB_READ_WRITE_TOKEN` is present (Vercel injects it once a Blob store
80
+ is connected), shots are staged in the system temp directory and uploaded to
81
+ Vercel Blob instead of `.polishd/snapshots/`. Pruning deletes the blobs;
82
+ a failed upload cleans up after itself so a half-stored snapshot never
83
+ survives. Blob pathnames get a random suffix and the dashboard still serves
84
+ every image through the auth-gated server action.
85
+ - When no local Chrome, Edge, or Playwright Chromium can launch on Linux,
86
+ capture falls back to `@sparticuz/chromium` — a Chromium built to run inside
87
+ Lambda-shaped sandboxes. It and `@vercel/blob` ship as optional
88
+ dependencies, so a standard `npm install` brings them along and
89
+ `--omit=optional` keeps them out.
90
+ - An install run with `--omit=optional` loses the feature but not the plot:
91
+ when the environment shows a missing optional dependency will be needed
92
+ (a Blob token with no `@vercel/blob`, a Vercel host with no
93
+ `@sparticuz/chromium`), the gallery says so up front and disables the
94
+ capture button, instead of failing a minute into a doomed run. Failures
95
+ that can only surface at capture time name the missing piece precisely.
96
+ - Local development is unchanged: your own Chrome first, images on disk,
97
+ same index, same gallery.
98
+
99
+ ### Reading is not friction: text clicks and trivial scrolls stop counting
100
+
101
+ Three signals could report engagement or frustration where there was only
102
+ reading, inflating exactly the numbers the AI summary leans on hardest.
103
+
104
+ - **Dead clicks skip text.** A click inside a paragraph, heading, list item,
105
+ or other prose block — or on standalone text long enough to read as content
106
+ (40+ chars) — is cursor placement or the start of a selection, not a user
107
+ expecting something to happen. It no longer records a `dead_click`. Clicks
108
+ on non-interactive *layout* elements still do, and so do short standalone
109
+ labels (`<div>Submit</div>`, `<span>Click here</span>`) — that shape is
110
+ exactly what a mis-wired fake control looks like.
111
+ - **Rage clicks skip select-a-word/paragraph.** Double- and triple-clicking
112
+ prose selects text; a rapid burst on a non-interactive text target no
113
+ longer records a `rage_click`. Hammering a real button — or a fake one with
114
+ a short label — still does.
115
+ - **History gets the same fix.** A one-time sweep (versioned via
116
+ `polishd_meta`, run on the first dashboard load after upgrading) re-runs
117
+ the new classification over already-stored `dead_click`/`rage_click` rows,
118
+ using the stored selector path and label. Matching rows are retyped to
119
+ `text_click` — kept in the table, counted by no aggregate — never deleted.
120
+ Rage rows whose selector path contains an interactive element are left
121
+ untouched. Ingest applies the same retype to arriving events, so a cached
122
+ client bundle — or a telemetry emitter still on an older package — can't
123
+ keep refilling the table with the old semantics after the sweep has run. Old `component_view` rows always carried a scroll depth, so at
124
+ read time depth from components short enough to fit a typical viewport
125
+ (≤700px) is ignored; page-level `scroll_depth` history is unaffected (a
126
+ recorded depth needed a real scroll event, and genuine deep scrolls can't
127
+ be told apart after the fact).
128
+ - **100% scroll requires somewhere to scroll.** A page (or dashboard region)
129
+ whose scrollable distance is under 10% of the viewport reaches "100%" by
130
+ existing, so it now records no `scroll_depth` at all; likewise
131
+ `<PolishdMonitor content>` only reports scroll-through for components
132
+ taller than one screen. Aggregates already treat absent as "no data" (shown
133
+ as —), never 0.
134
+ - Both capture layers (host site and the dashboard's own telemetry) share the
135
+ new classification via `src/client/dom.ts`, so they can't drift.
136
+ - The AI digest now omits scroll % where it wasn't measurable and the system
137
+ prompt tells the model these semantics — no more "users read to the bottom!"
138
+ wins on pages that fit in one viewport, and reported dead/rage counts can be
139
+ taken as genuine friction.
140
+
141
+ ### The "your proxy isn't running" banner stops crying wolf
142
+
143
+ A correctly installed, verifiably healthy site could show the red banner
144
+ indefinitely. The 0.2.2 rule compared an *all-time* drop total against an
145
+ all-time event total behind a one-hour recency gate, so the two halves covered
146
+ different time ranges: one fresh cookie-less batch — a crawler POSTing at the
147
+ public endpoint — re-armed every drop the install had ever recorded, including
148
+ the ones from before the proxy was first deployed. At the 1-in-400 ratio, 7
149
+ drops only needed fewer than 2,800 lifetime events to trip, which is most
150
+ personal sites for months.
151
+
152
+ - Drops are now bucketed by the hour, so the alert can compare drops and
153
+ stored events over **the same 24-hour window**. Records written before this
154
+ release carry no buckets, which means their history counts toward no window
155
+ and cannot re-arm anything.
156
+ - The strongest signal is now the cheapest one: an event stored *after* the
157
+ most recent drop proves the proxy is minting cookies right now, because
158
+ every event is attributed to that cookie and a broken proxy drops every
159
+ batch. No threshold to tune.
160
+ - Severity is split. Red — "your proxy isn't running" — is reserved for
161
+ nothing stored at all, or nothing stored in the window while drops keep
162
+ arriving. Otherwise the dashboard shows a neutral note: *N batches arrived
163
+ without a session cookie (bots, or visitors with cookies blocked) — X% of
164
+ traffic*, which is useful and true.
165
+ - "so nothing is being stored" only renders when nothing has been stored. It
166
+ used to sit directly above stat tiles counting stored sessions and events.
167
+ - The banner now points at `doctor --url <origin>` and says why: plain
168
+ `doctor` reads the source tree, so it can pass every check while a deployed
169
+ build still doesn't mint a cookie. Sending someone to a command that
170
+ answers "12 checks passed" was most of what made this alert expensive.
171
+ - The 60-second write collapse in `recordNoSession()` survives cold starts.
172
+ Its counters were module-level, so serverless reset them on every
173
+ invocation and the sparse traffic the throttle exists to absorb persisted
174
+ roughly 1:1; the durable `lastAt` now gates the write too.
175
+ - The rule lives in `src/shared/capture-status.ts` — pure, no database, no
176
+ React — with tests (`npm test`).
177
+
178
+ ### Site snapshots on the Design tab
179
+
180
+ The Design tab grows a **Site snapshots** card: one click screenshots every
181
+ scanned route of the site — phone and desktop, light and dark — and renders
182
+ the shots as a filterable gallery with a full-page lightbox. Capture runs
183
+ through the new `allpages` dependency (Playwright underneath), launching the
184
+ developer's own Chrome/Edge before falling back to Playwright's Chromium, and
185
+ never auto-downloads a browser. The origin is learned from the request that
186
+ rendered the dashboard (`POLISHD_SITE_ORIGIN` overrides); shots land under
187
+ `.polishd/snapshots/` (`POLISHD_SNAPSHOT_DIR` overrides, last 6 runs kept)
188
+ with only an index in the store, and every image travels to the browser
189
+ through an auth-guarded server action rather than a new public route. Each
190
+ snapshot is stamped with the design-metrics fingerprint at capture time — the
191
+ hook for before/after visual diffing as design suggestions get applied. This
192
+ is the package's first runtime dependency beyond the optional `pg`.
193
+
194
+ ### Errors are attributed to the code that threw them
195
+
196
+ `window` hears every throw in the tab, so an extension's failures — "Failed to
197
+ connect to MetaMask" being the canonical one — arrived as `js_error` events
198
+ indistinguishable from real bugs, often as the loudest error on the dashboard.
199
+
200
+ Rather than match error text, the client now works out *whose script threw*.
201
+ Resource Timing records every script the document actually fetched; extension
202
+ code is absent from it, because the browser injects content scripts and the
203
+ page never requested them. Comparing an error's stack against that live set
204
+ identifies injected code without knowing what it's called, so a new extension
205
+ needs no new pattern. Four verdicts come out: `site` (every frame is code you
206
+ shipped), `extension` (a frame names an extension URL scheme, including blobs
207
+ an extension minted at runtime), `foreign` (a frame names a script this
208
+ document never loaded), and `unknown` (nothing attributable — an opaque
209
+ cross-origin `Script error.`, an empty stack).
210
+
211
+ Only `extension` is dropped. `foreign` and `unknown` are kept, tagged with
212
+ `meta.origin`, and shown dimmed in Recent errors as "not your code" /
213
+ "unattributable" — a filter that silently eats what it can't identify is how a
214
+ real bug goes missing. A short list of message patterns remains as a last
215
+ resort for extension plumbing that throws with no attributable frame at all.
216
+
217
+ The drop also runs at ingest (a cached bundle can predate the filter, and the
218
+ endpoint is a public POST) and on the way out of `getRecentErrors`, so rows
219
+ written before this stop showing up too. New `ignoreErrors` config option —
220
+ strings matched case-insensitively, or regexes — drops anything else you've
221
+ decided not to chase.
222
+
223
+ ### Telemetry answers the product questions clicks can't
224
+
225
+ The dashboard telemetry emitter now sends one `install_state` event per
226
+ session — whether a model is connected and which provider/model, resolved
227
+ server-side, never the key — and the consent prompt discloses it. On the
228
+ collecting side, the Installs tab grew a "With a model" stat and a per-domain
229
+ Model column built from each install's latest report, so connecting,
230
+ switching, or disconnecting a model reads correctly.
231
+
232
+ The dashboard's own controls also carry `data-component` names now
233
+ (`ai-summary-refresh`, `ai-summary-generate`, `ai-connect-model`,
234
+ `journey-open`, `loss-file-bug`, `loss-ignore`, `design-review-refresh`,
235
+ `settings-scan-codebase`, `show-more`, coarse `settings`/`ai-summary`
236
+ containers, …), so with `POLISHD_ANALYTICS_SOURCE=telemetry` the collector's
237
+ Most-used-features table groups dashboard clicks by feature instead of raw
238
+ selectors — the same component-level story polishd tells its hosts, told
239
+ about itself. The attributes are inert for host apps.
240
+
3
241
  ## 0.2.2
4
242
 
5
243
  ### Cross-install telemetry ingest
package/README.md CHANGED
@@ -390,6 +390,27 @@ again.
390
390
  Ignoring a loss marks the summary stale, exactly like new analytics does, so
391
391
  the next refresh actually re-asks the model with the dismissal in hand.
392
392
 
393
+ ### The Issues tab
394
+
395
+ Filing a bug is easy to lose track of — it happens inside one loss, on one
396
+ summary, and then the summary regenerates. The **Issues** tab is the standing
397
+ list: every issue polishd has filed in the connected repo, newest first,
398
+ whether you clicked **File bug** yourself or auto-filing did it for you. The
399
+ tab only appears once a GitHub repository is connected.
400
+
401
+ Each row joins what polishd knows to what GitHub knows. The **evidence** — the
402
+ selector, component or path the analytics cited — and whether the source
403
+ verification confirmed the report are polishd's own record, kept at filing
404
+ time. The title, state, labels, assignees and comment count are read live from
405
+ GitHub on every render, so a bug someone closed an hour ago reads as closed
406
+ here, and the issue body is one click away without leaving the dashboard. An
407
+ issue that can no longer be read — deleted, transferred, or beyond what the
408
+ token now covers — keeps its row and says exactly that.
409
+
410
+ Opening the tab costs a single GitHub API call in the ordinary case, not one
411
+ per issue: the repo's issue list hands back a hundred whole issues at a time,
412
+ which is more than polishd is ever likely to have filed.
413
+
393
414
  ## Design review
394
415
 
395
416
  The dashboard's **Design** tab (in the sidebar) is your site's brand guideline
@@ -424,6 +445,33 @@ Nothing extra to install or wire: the scan ships with the existing client,
424
445
  flows through the existing ingest route, and the dashboard itself is never
425
446
  scanned.
426
447
 
448
+ ### Site snapshots
449
+
450
+ The Design tab can also **screenshot the site itself** — every scanned route,
451
+ phone and desktop, light and dark — and render the shots as a gallery, so the
452
+ measured tokens sit next to what the pages actually look like. Capture uses
453
+ [allpages](https://www.npmjs.com/package/allpages) (Playwright underneath): it
454
+ launches your installed Chrome or Edge, falling back to Playwright's Chromium
455
+ (`npx playwright install chromium` once, if you have neither). The origin to
456
+ shoot is taken from the request that rendered the dashboard, or set
457
+ `POLISHD_SITE_ORIGIN` to override it. Images live on disk under
458
+ `.polishd/snapshots/` (override with `POLISHD_SNAPSHOT_DIR`; the last 6
459
+ snapshots are kept), and each snapshot is stamped with the design-metrics
460
+ fingerprint at capture time — so a snapshot taken before a round of design
461
+ fixes can be held against one taken after.
462
+
463
+ **In production on Vercel**, capture works too — connect a
464
+ [Blob store](https://vercel.com/docs/vercel-blob) to the project and that's
465
+ the whole setup: the `BLOB_READ_WRITE_TOKEN` it injects switches image storage
466
+ from disk to Blob, and the browser comes from `@sparticuz/chromium` (a
467
+ Chromium built for serverless sandboxes, installed automatically as an
468
+ optional dependency). The snapshot index rides in the same database the rest
469
+ of Polishd already requires in production, so no other wiring changes. If a
470
+ capture of many routes brushes against your function's time limit, raise it
471
+ with `export const maxDuration = 300` in the dashboard's `page.tsx`. On hosts
472
+ with neither a writable filesystem nor a Blob token, the button explains what's
473
+ missing rather than failing silently.
474
+
427
475
  ## Component-level tracking
428
476
 
429
477
  Wrap any element to track it explicitly. Interactive controls get hover + click
@@ -459,6 +507,9 @@ once; nothing is sent unless you say yes. What's shared when you do:
459
507
  runs — and an anonymous per-browser-session id. No cookies, no
460
508
  fingerprinting, no URLs, page content, or user data from your site — your
461
509
  analytics never leave your database.
510
+ - Once per session, whether a **model is connected** and which provider/model
511
+ it is — never the key, never any setting beyond those two names. This is how
512
+ the project learns which AI setups to test against.
462
513
 
463
514
  Say no and it never asks again. Change your mind, or disable it fleet-wide,
464
515
  with `POLISHD_TELEMETRY=off`; `navigator.doNotTrack` is honored regardless of
@@ -488,9 +539,21 @@ import { definePolishdConfig } from "@polishd/next";
488
539
  export default definePolishdConfig({
489
540
  sampleRate: 1,
490
541
  rageClick: { count: 3, windowMs: 500 },
542
+ ignoreErrors: [],
491
543
  });
492
544
  ```
493
545
 
546
+ Browser-extension errors are never recorded. `window` hears every throw in the
547
+ tab, so an extension's failures — "Failed to connect to MetaMask" and its kin —
548
+ would otherwise show up as your site's noisiest bugs. Rather than match error
549
+ text, polishd asks whose script threw: the browser records every script your
550
+ document actually fetched, extension code is never among them, so an error
551
+ whose stack points outside that set is identifiable as injected without knowing
552
+ what it's called. Confident extension errors are dropped at capture and again
553
+ at ingest; errors that merely *can't* be attributed to your code are kept and
554
+ labelled, not hidden. `ignoreErrors` (strings, matched case-insensitively, or
555
+ regexes) drops anything else you'd rather not see.
556
+
494
557
  The dashboard never measures itself: nothing on `/polishd` (or below it) is
495
558
  captured, so reading your analytics can't show up as your site's most-used
496
559
  feature. **Moved the dashboard elsewhere?** Set `dashboardRoute` in your
package/bin/doctor.mjs CHANGED
@@ -349,8 +349,15 @@ function report(results, origin) {
349
349
  c.dim(`, ${results.filter((r) => r.status === PASS).length} checks passed`),
350
350
  );
351
351
  if (!origin) {
352
+ // "no problems" means the source tree is right, which is not the same as
353
+ // the deployed site minting cookies — a build that ships without the proxy
354
+ // passes every check here. Say so, so a green run isn't read as proof.
352
355
  console.log(
353
- c.dim("\nRun with --url http://localhost:3000 to also verify the cookie and ingest live."),
356
+ c.dim(
357
+ "\nThese are static checks on your source tree. Run with" +
358
+ " --url http://localhost:3000 (or your deployed origin) to verify the" +
359
+ " cookie and ingest on the running site.",
360
+ ),
354
361
  );
355
362
  }
356
363
  return fails > 0 ? 1 : 0;
@@ -1 +1 @@
1
- {"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../src/ai/digest.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAS9D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CA4FhF;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD"}
1
+ {"version":3,"file":"digest.d.ts","sourceRoot":"","sources":["../../src/ai/digest.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAS9D;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,oBAAoB,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CA+FhF;AAED,kFAAkF;AAClF,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD"}
package/dist/ai/digest.js CHANGED
@@ -55,10 +55,11 @@ export function buildDigest(data, context) {
55
55
  .sort((a, b) => b.score - a.score)
56
56
  .slice(0, 6);
57
57
  if (worst.length) {
58
- lines.push("PAGES WITH FRICTION (worst first):");
58
+ lines.push("PAGES WITH FRICTION (worst first; scroll depth is only measured on pages tall enough to scroll — absent means no signal, not disengagement):");
59
59
  for (const p of worst) {
60
+ const scroll = p.avgScrollDepth === null ? "" : `, scroll ${r(p.avgScrollDepth)}%`;
60
61
  lines.push(` - ${p.path}: ${p.sessions} sessions, ${p.rageClicks} rage, ` +
61
- `${p.deadClicks} dead, ${p.jsErrors} err, scroll ${r(p.avgScrollDepth)}%`);
62
+ `${p.deadClicks} dead, ${p.jsErrors} err${scroll}`);
62
63
  }
63
64
  }
64
65
  const brokenEls = elements.filter((e) => e.rageClicks > 0 || e.deadClicks > 0).slice(0, 8);
@@ -1 +1 @@
1
- {"version":3,"file":"digest.js","sourceRoot":"","sources":["../../src/ai/digest.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"digest.js","sourceRoot":"","sources":["../../src/ai/digest.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import type { PolishdGithubStatus, VerifyGithubResult } from "./types";
1
+ import type { PolishdGithubIssue, PolishdGithubStatus, VerifyGithubResult } from "./types";
2
2
  /** True when both a repo and a token are configured. */
3
3
  export declare function isGithubConnected(): Promise<boolean>;
4
4
  /**
@@ -39,6 +39,27 @@ export declare function createGithubPullRequest(input: {
39
39
  url: string;
40
40
  number: number;
41
41
  }>;
42
+ /**
43
+ * Read one issue by number. Returns null when it can't be read — deleted,
44
+ * transferred, or the token lost access — so a single missing issue never
45
+ * takes down the list that contains it.
46
+ */
47
+ export declare function readGithubIssue(number: number): Promise<PolishdGithubIssue | null>;
48
+ /**
49
+ * Read a known set of issues by number, in as few API calls as possible.
50
+ *
51
+ * The naive way — one call per number — is what the repo's own issue list
52
+ * saves us from: it returns whole issue objects, body and all, a hundred at a
53
+ * time, so a single call usually answers for every issue polishd has ever
54
+ * filed. When to stop asking for pages is its own rule, in issue-pages.ts.
55
+ *
56
+ * Anything the pages didn't reach is read individually afterwards, which is
57
+ * also the whole strategy when there's only one number to find.
58
+ *
59
+ * Numbers that can't be read at all (deleted, transferred, token access
60
+ * narrowed) are simply absent from the returned map.
61
+ */
62
+ export declare function readGithubIssues(numbers: number[]): Promise<Map<number, PolishdGithubIssue>>;
42
63
  /** File an issue in the connected repo. Throws on failure. */
43
64
  export declare function createGithubIssue(input: {
44
65
  title: string;
@@ -1 +1 @@
1
- {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/ai/github.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAavE,wDAAwD;AACxD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAE1D;AA0CD;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CA2B1E;AAED,gFAAgF;AAChF,wBAAsB,eAAe,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAG3E;AAID;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,SAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAclF;AAID;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAa3C;AAID,8DAA8D;AAC9D,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAU3C"}
1
+ {"version":3,"file":"github.d.ts","sourceRoot":"","sources":["../../src/ai/github.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,SAAS,CAAC;AAajB,wDAAwD;AACxD,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,OAAO,CAAC,CAE1D;AA0CD;;;;GAIG;AACH,wBAAsB,sBAAsB,IAAI,OAAO,CAAC,kBAAkB,CAAC,CA2B1E;AAED,gFAAgF;AAChF,wBAAsB,eAAe,IAAI,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC,CAG3E;AAID;;;;GAIG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,GAAG,CAAC,EAAE,MAAM,GACX,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAcxB;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,SAAI,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAclF;AAID;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,MAAM,GACZ,OAAO,CAAC,MAAM,CAAC,CAgBjB;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,CAAC,KAAK,EAAE;IACnD,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAa3C;AA2CD;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAUxF;AAKD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EAAE,GAChB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CA4C1C;AAED,8DAA8D;AAC9D,wBAAsB,iBAAiB,CAAC,KAAK,EAAE;IAC7C,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAU3C"}
package/dist/ai/github.js CHANGED
@@ -5,14 +5,16 @@
5
5
  * onboarding. Capabilities, all scoped to that one repo: read and search source
6
6
  * (Contents + code-search APIs — lets the AI layer ground its findings in real
7
7
  * code even where the source tree isn't on disk, e.g. Vercel), create branches,
8
- * open pull requests, and file issues. The "loss → verified bug" orchestration
9
- * that uses this client lives in issues.ts.
8
+ * open pull requests, and file issues — then read those issues back, which is
9
+ * what the dashboard's Issues tab lists. The "loss → verified bug"
10
+ * orchestration that uses this client lives in issues.ts.
10
11
  *
11
12
  * The token lives in the same server-side settings blob as the model API key
12
13
  * and never reaches the browser; the client only sees a "connected" flag. A
13
14
  * fine-grained PAT with Contents (read), Issues (write), and Pull requests
14
15
  * (write) on the one repo is all it needs.
15
16
  */
17
+ import { ISSUE_PAGE_SIZE, keepPaging, worthListing, } from "./issue-pages";
16
18
  import { resolveSettings } from "./settings";
17
19
  const API = "https://api.github.com";
18
20
  /** The connected repo + token, or null when either half is missing. */
@@ -163,7 +165,101 @@ export async function createGithubPullRequest(input) {
163
165
  const pr = await gh(conn.token, "POST", `/repos/${conn.repo}/pulls`, { title: input.title, body: input.body ?? "", head: input.head, base });
164
166
  return { url: pr.html_url, number: pr.number };
165
167
  }
166
- // ── Issues ───────────────────────────────────────────────────────────────────
168
+ function toIssue(raw) {
169
+ return {
170
+ number: raw.number,
171
+ title: raw.title,
172
+ body: raw.body ?? "",
173
+ url: raw.html_url,
174
+ state: raw.state === "closed" ? "closed" : "open",
175
+ stateReason: raw.state_reason ?? undefined,
176
+ labels: (raw.labels ?? [])
177
+ .map((l) => (typeof l === "string" ? l : l.name))
178
+ .filter((n) => typeof n === "string" && n.length > 0),
179
+ author: raw.user?.login ?? undefined,
180
+ assignees: (raw.assignees ?? [])
181
+ .map((a) => a.login)
182
+ .filter((n) => typeof n === "string" && n.length > 0),
183
+ comments: raw.comments ?? 0,
184
+ createdAt: Date.parse(raw.created_at),
185
+ updatedAt: Date.parse(raw.updated_at),
186
+ closedAt: raw.closed_at ? Date.parse(raw.closed_at) : undefined,
187
+ };
188
+ }
189
+ /**
190
+ * Read one issue by number. Returns null when it can't be read — deleted,
191
+ * transferred, or the token lost access — so a single missing issue never
192
+ * takes down the list that contains it.
193
+ */
194
+ export async function readGithubIssue(number) {
195
+ const conn = await connection();
196
+ if (!conn)
197
+ return null;
198
+ try {
199
+ return toIssue(await gh(conn.token, "GET", `/repos/${conn.repo}/issues/${number}`));
200
+ }
201
+ catch {
202
+ return null;
203
+ }
204
+ }
205
+ /** How many individual issue reads run at once, when it comes to that. */
206
+ const ISSUE_FETCH_CONCURRENCY = 6;
207
+ /**
208
+ * Read a known set of issues by number, in as few API calls as possible.
209
+ *
210
+ * The naive way — one call per number — is what the repo's own issue list
211
+ * saves us from: it returns whole issue objects, body and all, a hundred at a
212
+ * time, so a single call usually answers for every issue polishd has ever
213
+ * filed. When to stop asking for pages is its own rule, in issue-pages.ts.
214
+ *
215
+ * Anything the pages didn't reach is read individually afterwards, which is
216
+ * also the whole strategy when there's only one number to find.
217
+ *
218
+ * Numbers that can't be read at all (deleted, transferred, token access
219
+ * narrowed) are simply absent from the returned map.
220
+ */
221
+ export async function readGithubIssues(numbers) {
222
+ const found = new Map();
223
+ const conn = await connection();
224
+ if (!conn || numbers.length === 0)
225
+ return found;
226
+ const wanted = new Set(numbers);
227
+ const oldestWanted = Math.min(...numbers);
228
+ let pagesRead = 0;
229
+ let morePages = worthListing(wanted.size);
230
+ while (morePages) {
231
+ let batch;
232
+ try {
233
+ batch = await gh(conn.token, "GET", `/repos/${conn.repo}/issues?state=all&per_page=${ISSUE_PAGE_SIZE}&page=${pagesRead + 1}`);
234
+ }
235
+ catch {
236
+ break; // fall through to the per-issue reads
237
+ }
238
+ pagesRead++;
239
+ let lowestSeen = Infinity;
240
+ for (const raw of batch) {
241
+ if (wanted.has(raw.number))
242
+ found.set(raw.number, toIssue(raw));
243
+ lowestSeen = Math.min(lowestSeen, raw.number);
244
+ }
245
+ morePages = keepPaging({
246
+ pagesRead,
247
+ batchSize: batch.length,
248
+ lowestSeen,
249
+ oldestWanted,
250
+ outstanding: wanted.size - found.size,
251
+ });
252
+ }
253
+ const missing = numbers.filter((n) => !found.has(n));
254
+ for (let i = 0; i < missing.length; i += ISSUE_FETCH_CONCURRENCY) {
255
+ const slice = missing.slice(i, i + ISSUE_FETCH_CONCURRENCY);
256
+ for (const issue of await Promise.all(slice.map((n) => readGithubIssue(n)))) {
257
+ if (issue)
258
+ found.set(issue.number, issue);
259
+ }
260
+ }
261
+ return found;
262
+ }
167
263
  /** File an issue in the connected repo. Throws on failure. */
168
264
  export async function createGithubIssue(input) {
169
265
  const conn = await connection();
@@ -1 +1 @@
1
- {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/ai/github.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAG7C,MAAM,GAAG,GAAG,wBAAwB,CAAC;AAErC,uEAAuE;AACvE,KAAK,UAAU,UAAU;IACvB,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,EAAE,CAAC;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;IACzC,MAAM,KAAK,GAAG,QAAQ,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,OAAO,CAAC,MAAM,UAAU,EAAE,CAAC,KAAK,IAAI,CAAC;AACvC,CAAC;AAED,wEAAwE;AACxE,KAAK,UAAU,EAAE,CACf,KAAa,EACb,MAAc,EACd,IAAY,EACZ,IAAc;IAEd,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,GAAG,GAAG,IAAI,EAAE,EAAE;QACvC,MAAM;QACN,OAAO,EAAE;YACP,aAAa,EAAE,UAAU,KAAK,EAAE;YAChC,MAAM,EAAE,6BAA6B;YACrC,sBAAsB,EAAE,YAAY;YACpC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACtE;QACD,IAAI,EAAE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;QAC3D,KAAK,EAAE,UAAU;KAClB,CAAC,CAAC;IACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACZ,IAAI,OAAO,GAAG,oBAAoB,GAAG,CAAC,MAAM,EAAE,CAAC;QAC/C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAyB,CAAC;YACvD,IAAI,GAAG,CAAC,OAAO;gBAAE,OAAO,GAAG,WAAW,GAAG,CAAC,OAAO,KAAK,GAAG,CAAC,MAAM,GAAG,CAAC;QACtE,CAAC;QAAC,MAAM,CAAC;YACP,kCAAkC;QACpC,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAM,CAAC;AACjC,CAAC;AAWD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,sBAAsB;IAC1C,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,eAAe;YACtB,OAAO,EAAE,0CAA0C;SACpD,CAAC;IACJ,CAAC;IACD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAe,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QAC9E,OAAO;YACL,EAAE,EAAE,IAAI;YACR,MAAM,EAAE;gBACN,IAAI,EAAE,IAAI,CAAC,SAAS;gBACpB,aAAa,EAAE,IAAI,CAAC,cAAc;gBAClC,OAAO,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,KAAK,IAAI;gBACxC,aAAa,EAAE,IAAI,CAAC,UAAU;aAC/B;SACF,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,EAAE,EAAE,KAAK;YACT,KAAK,EAAE,cAAc;YACrB,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,yBAAyB;SACxE,CAAC;IACJ,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,GAAG,GAAG,MAAM,sBAAsB,EAAE,CAAC;IAC3C,OAAO,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC;AACpC,CAAC;AAED,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,IAAY,EACZ,GAAY;IAEZ,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACvB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,EAAE,CACnB,IAAI,CAAC,KAAK,EACV,KAAK,EACL,UAAU,IAAI,CAAC,IAAI,aAAa,SAAS,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,QAAQ,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CACjG,CAAC;QACF,IAAI,IAAI,CAAC,QAAQ,KAAK,QAAQ,IAAI,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAChF,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC9D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAe,EAAE,GAAG,GAAG,CAAC;IAC7D,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC3C,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,kBAAkB,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;QACrE,MAAM,GAAG,GAAG,MAAM,EAAE,CAClB,IAAI,CAAC,KAAK,EACV,KAAK,EACL,kBAAkB,CAAC,aAAa,GAAG,EAAE,CACtC,CAAC;QACF,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5D,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gFAAgF;AAEhF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,IAAY,EACZ,IAAa;IAEb,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvD,MAAM,IAAI,GACR,IAAI;QACJ,CAAC,MAAM,EAAE,CAAe,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC;IACpF,MAAM,GAAG,GAAG,MAAM,EAAE,CAClB,IAAI,CAAC,KAAK,EACV,KAAK,EACL,UAAU,IAAI,CAAC,IAAI,kBAAkB,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAChE,CAAC;IACF,MAAM,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,IAAI,CAAC,IAAI,WAAW,EAAE;QAC3D,GAAG,EAAE,cAAc,IAAI,EAAE;QACzB,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG;KACpB,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,KAK7C;IACC,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvD,MAAM,IAAI,GACR,KAAK,CAAC,IAAI;QACV,CAAC,MAAM,EAAE,CAAe,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC;IACpF,MAAM,EAAE,GAAG,MAAM,EAAE,CACjB,IAAI,CAAC,KAAK,EACV,MAAM,EACN,UAAU,IAAI,CAAC,IAAI,QAAQ,EAC3B,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,IAAI,EAAE,CACvE,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,CAAC;AACjD,CAAC;AAED,gFAAgF;AAEhF,8DAA8D;AAC9D,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,KAIvC;IACC,MAAM,IAAI,GAAG,MAAM,UAAU,EAAE,CAAC;IAChC,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACvD,MAAM,KAAK,GAAG,MAAM,EAAE,CACpB,IAAI,CAAC,KAAK,EACV,MAAM,EACN,UAAU,IAAI,CAAC,IAAI,SAAS,EAC5B,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CACrE,CAAC;IACF,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC;AACvD,CAAC"}
1
+ {"version":3,"file":"github.js","sourceRoot":"","sources":["../../src/ai/github.ts"],"names":[],"mappings":"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"}