git-history-ui 3.2.0 → 3.2.2

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.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,35 @@ All notable changes to this project are documented in this file.
4
4
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
5
5
  this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [3.2.2] - 2026-05-02
8
+
9
+ ### Changed
10
+
11
+ - Hardened large-repo performance: insights now use a single `git log --numstat`
12
+ pass, SQLite indexing streams git output instead of buffering full logs, and
13
+ the commit graph keeps its canvas viewport-sized so it remains smooth beyond
14
+ browser canvas-height limits.
15
+
16
+ ### Fixed
17
+
18
+ - Preserved rename semantics in churn calculations, safely rejected streaming
19
+ callback failures, and protected streamed index builds from UTF-8 chunk
20
+ boundary corruption.
21
+
22
+ ## [3.2.1] - 2026-05-02
23
+
24
+ ### Fixed
25
+
26
+ - **`npx git-history-ui` no longer prints help and exits.** When the
27
+ `presets` subcommand was added in v3.2.0, the root commander program
28
+ was left without a default `.action()`. Commander v12 reacts to that
29
+ by printing help and exiting whenever the user invokes the binary
30
+ without a subcommand. A no-args invocation now correctly starts the
31
+ server, matching pre-v3.2.0 behavior.
32
+ - Added a CLI smoke test (`src/__tests__/cli.test.ts`) that runs the
33
+ built binary with `--help`, `--version`, and no args so this kind of
34
+ regression can't ship silently again.
35
+
7
36
  ## [3.2.0] - 2026-05-02
8
37
 
9
38
  The "Distribution & scale" release. This phase makes the tool faster on big
package/README.md CHANGED
@@ -5,136 +5,175 @@
5
5
  [![npm license](https://img.shields.io/npm/l/git-history-ui.svg)](https://www.npmjs.com/package/git-history-ui)
6
6
  [![npm bundle size](https://img.shields.io/bundlephobia/min/git-history-ui.svg)](https://bundlephobia.com/result?p=git-history-ui)
7
7
  [![GitHub stars](https://img.shields.io/github/stars/beingmartinbmc/git-history-ui.svg)](https://github.com/beingmartinbmc/git-history-ui)
8
- [![GitHub issues](https://img.shields.io/github/issues/beingmartinbmc/git-history-ui.svg)](https://github.com/beingmartinbmc/git-history-ui/issues)
9
8
 
10
- **Git Intelligence in your browser.** A fast, zero-setup web UI that turns your
11
- git history from a flat log into a navigable narrative — with natural-language
12
- search, PR/feature grouping, time-travel snapshots, file-level history, blame,
13
- commit impact analysis, and an insights dashboard. Optional AI integration
14
- (Anthropic / OpenAI) supercharges search and explanations.
9
+ **Git Intelligence in your browser.**
10
+
11
+ Turn your git history into something you can actually understand:
12
+
13
+ - 🔎 Ask questions in plain English
14
+ - 📦 See commits grouped by feature or PR
15
+ - 🕰️ Travel through time and diff any state
16
+ - 🎯 Understand impact, not just changes
17
+
18
+ Zero setup. Runs locally. Your code never leaves your machine unless you opt in.
19
+
20
+ ```bash
21
+ npx git-history-ui@latest
22
+ ```
23
+
24
+ ## ⚡ 10-second workflow
25
+
26
+ 1. Run `npx git-history-ui` inside any git repo
27
+ 2. Search: *"login bug last month"*
28
+ 3. Jump to the commit
29
+ 4. Inspect the diff and what it impacted
30
+
31
+ Done.
15
32
 
16
33
  ## 👀 Preview
17
34
 
18
35
  ![Git History UI screenshot](./docs/screenshot.png)
19
36
 
37
+ > A demo GIF showing NL search, the timeline slider, and grouped view is on
38
+ > the way. In the meantime, `npx git-history-ui@latest` is the fastest way
39
+ > to see it for yourself — it opens in your browser in under a second.
40
+
41
+ ## 🤔 Why this exists
42
+
43
+ Git history is hard to understand:
44
+
45
+ - commits are flat
46
+ - context is missing
47
+ - debugging across branches is painful
48
+ - GitHub's UI hides your local and unpushed work
49
+
50
+ `git-history-ui` turns that history into something **searchable, grouped,
51
+ explorable, and explainable** — without a desktop install or a cloud
52
+ account.
53
+
54
+ ## ✨ What makes it different
55
+
56
+ Four things you don't get from `git log`, GitHub, or most desktop clients:
57
+
58
+ - **Natural-language search.** "login bug last month", "payments by alice".
59
+ A heuristic intent parser handles dates, authors, and keyword synonyms;
60
+ optional Anthropic / OpenAI key adds semantic re-ranking on top.
61
+ - **PR & feature grouping.** Switch the commit list to *Grouped* mode to
62
+ see commits clustered by pull request or Conventional Commits scope.
63
+ - **Time-travel timeline.** A horizontal slider that scrubs the repo state
64
+ at any point in time and live-diffs it against HEAD.
65
+ - **Commit impact analysis.** One click reveals which files, modules, and
66
+ related commits a change actually touches — not just the diff.
67
+
68
+ ## 🤝 AI is optional, opt-in, and on your key
69
+
70
+ - Heuristic mode works out of the box, no key required.
71
+ - Set `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` to upgrade NL search ranking
72
+ and unlock "Explain change" / "Summarize diff" actions.
73
+ - Prompts run from your machine to your provider. Your repo, your key,
74
+ your call.
75
+
20
76
  ## 🚀 Quick Start
21
77
 
22
78
  ```bash
23
- # Go to the git repository you want to inspect
24
79
  cd /path/to/your/project
25
-
26
- # Run directly with npx (no installation needed)
27
80
  npx git-history-ui@latest
28
81
  ```
29
82
 
30
- That's it! The application will start on `http://localhost:3000` and open your browser automatically.
31
- It reads history from the current working directory, so run it inside the project whose commits you want to visualize.
83
+ That's it. The app starts on `http://localhost:3000` and opens your
84
+ browser automatically. It reads history from the current working
85
+ directory — no installs, no config, no account.
32
86
 
33
- No installs. No config. Just your commits, visualized.
87
+ ## ⚖️ How it compares
34
88
 
35
- ## 🤔 Why use this?
89
+ - **vs GitHub UI:** NL search and PR grouping work *with* your unpushed
90
+ commits. Time travel and impact analysis aren't on GitHub at all.
91
+ - **vs `tig` / `git log`:** visual lanes, browser diffs, optional AI
92
+ explanations, insights dashboard.
93
+ - **vs desktop clients (GitKraken, SourceTree, Fork):** starts on demand,
94
+ no project import, no account, no native install. AI features are
95
+ pay-as-you-go on *your* key — nothing about your code leaves your
96
+ machine unless you opt in.
36
97
 
37
- - `git log` is powerful, but hard to scan when branches, merges, and long-lived work overlap.
38
- - GitHub's commit UI does not show your local or unpushed commits.
39
- - Desktop clients can be heavy when you just want a quick read on one repo.
40
- - `git-history-ui` gives you a fast, local, visual way to explore history from any git repository.
98
+ ## 📦 All features
41
99
 
42
- ## ⚡ New in v3.2 — Distribution & scale
100
+ <details>
101
+ <summary><strong>Click to expand the full feature list</strong></summary>
43
102
 
44
- - **SQLite indexer (optional)** — When `better-sqlite3` is installed, large
45
- repos get an FTS5-backed index in `~/.git-history-ui/`. Falls back to
46
- git-shelling silently if the native module isn't available.
47
- Endpoints: `GET /api/index/stats`, `POST /api/index/build`.
48
- - **Streaming commits** — `GET /api/commits/stream` (SSE) progressively
49
- pushes commits as `git log` produces them.
50
- - **Virtualized commit graph** — The canvas only paints rows currently on
51
- screen, so 50k-commit histories scroll without dropping frames.
52
- - **Shareable URLs** — `POST /api/share` returns a deep link with view-state
53
- encoded in the query string (no relay server needed for the common case).
54
- - **CLI presets** — `--preset <name>` / `--save-preset <name>` and
55
- `git-history-ui presets list|delete`, stored in
56
- `~/.git-history-ui/presets.json`.
57
- - **Embeds** — Chrome extension scaffold (`apps/chrome-extension/`) and
58
- GitHub App scaffold (`apps/github-app/`) that add a "View in
59
- git-history-ui" button to GitHub PR / commit pages.
60
-
61
- ## ✨ What's new in v3 — "Git Intelligence"
62
-
63
- - **Natural-language search** — Ask "login bug last month" or "payments by alice".
64
- A built-in heuristic intent parser extracts dates, authors, and keyword
65
- synonyms; if you set `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`, it adds
66
- semantic re-ranking on top.
67
- - **PR & feature grouping** — Switch the commit list to "Grouped" mode to see
68
- commits clustered by pull request (GitHub merge & squash patterns) or
69
- Conventional Commits scope (`feat(auth):`, `fix(payments):`). Optional
70
- GitHub PR enrichment when `GITHUB_TOKEN` is set.
71
- - **Time travel** — A horizontal timeline slider that shows the repo state
72
- (HEAD, branches, tags) at any point and computes a live diff vs HEAD.
73
- - **File history & blame** — Click any file in a commit's Files panel to see
74
- every commit that touched it, with a tabbed blame view powered by
75
- `highlight.js`.
76
- - **Commit impact analysis** — One click reveals files touched, modules
77
- affected, dependency ripple (parsed from JS/TS imports), and other commits
78
- that touched the same files.
79
- - **Insights dashboard** — Top contributors, hotspots, churn over time, and
80
- a heuristic risky-files score for code reviewers and tech leads.
81
- - **AI extras (optional)** — "Explain this change" on commits and "Summarize"
82
- on diffs, both gated on a configured API key.
83
- - **Local-first annotations** — Add notes to commits stored at
84
- `~/.git-history-ui/<repo>/annotations.json`.
103
+ ### Exploration
85
104
 
86
- Plus everything from v2:
105
+ - **Canvas commit graph** with branch lanes, ref pills, hover/selected
106
+ states; viewport-virtualized so 50k-commit histories stay smooth.
107
+ - **Real-time filtering** by author, date, text, file path.
108
+ - **Unified & split diffs** with `highlight.js`, collapse-unchanged
109
+ blocks, side-by-side scroll-sync, and intra-line word highlighting.
110
+ - **Dark / light / system theme** with single-click toggle.
87
111
 
88
- - **Canvas commit graph** with branch lanes, ref pills, hover/selected states
89
- - **Real-time filtering** by author, date, text, file path
90
- - **Unified & split diffs** with `highlight.js`, plus collapse-unchanged blocks
91
- - **Dark / light / system theme** with single-click toggle
92
- - **Zero setup** — `npx git-history-ui@latest`, that's it
112
+ ### Code understanding
93
113
 
94
- ## ⚖️ How it compares
114
+ - **File-level history.** Click any file in a commit to see every commit
115
+ that touched it.
116
+ - **Blame view** powered by `highlight.js`, tabbed inside file history.
117
+ - **Insights dashboard.** Top contributors, hotspots (treemap), churn
118
+ over time (d3 area chart), heuristic risky-files score.
119
+ - **Commit impact card.** Files touched, modules affected, dependency
120
+ ripple parsed from JS/TS imports, related commits — including a d3
121
+ force-directed graph view.
95
122
 
96
- - **vs GitHub UI**: NL search and PR grouping work *with* your unpushed
97
- commits, and time travel + impact analysis aren't on GitHub at all.
98
- - **vs `tig` or `git log`**: visual lanes, browser diffs, AI explanations,
99
- insights dashboard.
100
- - **vs desktop clients (GitKraken, SourceTree, Fork)**: starts on demand with
101
- no project import, no account, no native install. AI features are
102
- pay-as-you-go on *your* key — nothing about your code leaves your machine
103
- unless you opt in.
123
+ ### Collaboration
104
124
 
105
- ## 📖 Usage
125
+ - **Local-first annotations.** Per-commit comment threads stored in
126
+ `~/.git-history-ui/<repo>/annotations.json`.
127
+ - **Shareable URLs.** `POST /api/share` returns a deep link with the
128
+ current view-state encoded in the query string — no relay server
129
+ required for the common case.
130
+ - **"Explain this change"** AI card on the commit detail panel (opt-in).
106
131
 
107
- ### CLI Options
132
+ ### Performance & scale
108
133
 
109
- Run these commands from inside the git repository you want to inspect.
134
+ - **SQLite indexer (optional).** Install `better-sqlite3` and large
135
+ repos get an FTS5-backed index in `~/.git-history-ui/`. Silent
136
+ fallback to git-shelling when the native module isn't available.
137
+ Endpoints: `GET /api/index/stats`, `POST /api/index/build`.
138
+ - **Streaming commits.** `GET /api/commits/stream` (SSE) pushes commits
139
+ as `git log` produces them.
140
+ - **Virtualized commit graph.** Only the visible viewport is painted;
141
+ scrolling is `requestAnimationFrame`-throttled.
110
142
 
111
- ```bash
112
- # Custom port
113
- npx git-history-ui@latest --port 8080
143
+ ### CLI
114
144
 
115
- # Filter by specific file
116
- npx git-history-ui@latest --file src/app.js
145
+ - **Presets.** `--preset <name>` / `--save-preset <name>` and a
146
+ `git-history-ui presets list|delete` subcommand, stored in
147
+ `~/.git-history-ui/presets.json`.
148
+ - **Standard filters.** `--file`, `--author`, `--since`, `--port`,
149
+ `--no-open`, `--cwd`, `--llm <provider>`.
117
150
 
118
- # Filter by author
119
- npx git-history-ui@latest --author "your-name"
151
+ ### Embeds (experimental scaffolds)
120
152
 
121
- # Filter by date range
122
- npx git-history-ui@latest --since 2024-01-01
153
+ - **Chrome extension** (`apps/chrome-extension/`) injects a "View in
154
+ git-history-ui" button on github.com PR / commit pages.
155
+ - **GitHub App** (`apps/github-app/`) scaffold for the same deep-link
156
+ strategy at the org level.
123
157
 
124
- # Don't auto-open browser
125
- npx git-history-ui@latest --no-open
158
+ See [`CHANGELOG.md`](./CHANGELOG.md) for per-version detail.
126
159
 
127
- # Show help
128
- npx git-history-ui@latest --help
160
+ </details>
161
+
162
+ ## 📖 Usage
163
+
164
+ Run from inside the git repository you want to inspect.
165
+
166
+ ```bash
167
+ npx git-history-ui@latest --port 8080 # custom port
168
+ npx git-history-ui@latest --file src/app.js # filter by file
169
+ npx git-history-ui@latest --author "alice" # filter by author
170
+ npx git-history-ui@latest --since 2024-01-01 # filter by date
171
+ npx git-history-ui@latest --no-open # don't open the browser
172
+ npx git-history-ui@latest --help # full flag list
129
173
  ```
130
174
 
131
175
  ### Optional: bring your own AI key
132
176
 
133
- Natural-language search and "Explain change" / "Summarize diff" actions all
134
- work without an API key (heuristic mode). Set one of these to upgrade them
135
- with a real model — your code never leaves the host running git-history-ui
136
- except for the prompt you explicitly trigger:
137
-
138
177
  ```bash
139
178
  # Anthropic (recommended; uses claude-3-5-haiku by default)
140
179
  export ANTHROPIC_API_KEY=sk-ant-...
@@ -143,65 +182,46 @@ export ANTHROPIC_API_KEY=sk-ant-...
143
182
  export OPENAI_API_KEY=sk-...
144
183
 
145
184
  # Force a specific provider when both are set
146
- export GHUI_LLM_PROVIDER=anthropic # or openai, or heuristic
147
-
148
- npx git-history-ui@latest
185
+ export GHUI_LLM_PROVIDER=anthropic # anthropic | openai | heuristic
149
186
  ```
150
187
 
151
188
  ### Optional: GitHub PR enrichment
152
189
 
153
- Set `GITHUB_TOKEN` (a fine-grained PAT with read access to your repo) to
154
- hydrate the grouped view with PR titles, authors, and labels:
155
-
156
190
  ```bash
157
- export GITHUB_TOKEN=ghp_...
158
- npx git-history-ui@latest
191
+ export GITHUB_TOKEN=ghp_... # fine-grained PAT, read-only on the repo
159
192
  ```
160
193
 
194
+ This hydrates the *Grouped* view with PR titles, authors, and labels.
195
+
161
196
  ## 🏭 Production
162
197
 
163
- ### Build for Production
164
198
  ```bash
165
- # Build both backend and frontend
166
- npm run build:production
167
-
168
- # Start production server
169
- npm run start:production
199
+ npm run build:production # build backend + frontend
200
+ npm run start:production # start the production server
170
201
  ```
171
202
 
172
203
  ### Docker
204
+
173
205
  ```bash
174
- # Build and run with Docker
175
206
  docker build -t git-history-ui .
176
207
  docker run -p 3000:3000 git-history-ui
177
208
  ```
178
209
 
179
210
  ## 🛠️ Development
180
211
 
181
- ### Setup
182
212
  ```bash
183
- # Clone and install
184
213
  git clone https://github.com/beingmartinbmc/git-history-ui.git
185
214
  cd git-history-ui
186
215
  npm install
187
-
188
- # Start development servers
189
- npm run dev
190
- ```
191
-
192
- ### Testing
193
- ```bash
194
- # Run backend tests
195
- npm test
196
-
197
- # Run frontend tests
216
+ npm run dev # runs backend + frontend with hot reload
217
+ npm test # backend tests
198
218
  cd frontend && npm test
199
219
  ```
200
220
 
201
221
  ## 📋 Requirements
202
222
 
203
- - **Node.js**: 20.19.0 or higher, or 22.12.0 or higher
204
- - **Git**: Any version (must be in a git repository)
223
+ - **Node.js**: 20.19.0+ or 22.12.0+
224
+ - **Git**: any version (must be in a git repository)
205
225
 
206
226
  ## 🤝 Contributing
207
227
 
@@ -213,8 +233,12 @@ cd frontend && npm test
213
233
 
214
234
  ## 📄 License
215
235
 
216
- MIT License - see [LICENSE](LICENSE) file for details
236
+ MIT see [LICENSE](LICENSE).
217
237
 
218
238
  ---
219
239
 
220
- Made with ❤️ for developers who love beautiful git visualizations
240
+ ## If this saved you time
241
+
242
+ [Star the repo](https://github.com/beingmartinbmc/git-history-ui) — it
243
+ helps more developers discover it, and it tells me which features to
244
+ double down on.
@@ -0,0 +1,2 @@
1
+ import{a as Xt,b as Jt,c as mn}from"./chunk-36NFLS3P.js";import{a as nn}from"./chunk-R33W2FKN.js";import{a as Zt,b as Qt,c as qt,h as Kt}from"./chunk-YSTG766K.js";import{a as en}from"./chunk-NUMLL3OZ.js";import{a as G}from"./chunk-N7UHDKJ7.js";import{e as on,f as rn,g as an,h as sn,i as ln,j as cn,k as dn}from"./chunk-QUDEGJKI.js";import{d as Yt}from"./chunk-3FFYILBL.js";import{a as tn}from"./chunk-ITIFFECZ.js";import{$ as f,$a as Tt,Ab as _,B as ht,Bb as B,C as Me,Cb as Ne,D as _t,Db as Bt,Ea as Pe,Fb as tt,Ga as s,Gb as nt,Hb as it,I as vt,Ia as Dt,Ja as Je,Jb as ue,Ka as kt,Lb as he,Ma as Pt,Mb as _e,N as Ct,Ob as Ve,P as xt,Pa as D,Q as Xe,Qa as pe,R as Oe,Ra as oe,Rb as jt,S as Ee,Sa as et,Sb as ee,Ta as v,Tb as j,V as bt,Va as Rt,W as V,Wa as fe,Wb as Gt,X as de,Xa as It,Xb as Ht,Z as Q,Zb as $t,ab as ge,db as u,dc as U,e as pt,ea as M,eb as l,ec as I,fa as O,fb as a,fc as Fe,g as Ke,ga as wt,gb as b,hb as Nt,hc as T,i as ft,ib as Vt,j as N,ja as yt,jb as Ft,ka as De,kb as Re,la as St,lb as Ie,lc as Wt,m as gt,mb as F,mc as Ut,n as ut,nb as S,nc as ze,oa as x,ob as C,pb as zt,q as W,qa as Mt,qb as Lt,ra as Ot,s as Se,sa as ke,sb as q,tb as K,ub as X,va as me,vb as Te,wb as J,xb as z,yb as At,za as Et,zb as c}from"./chunk-TQE5NWMZ.js";var Le=class i{http=f(ze);base="/api";list(n){return this.http.get(`${this.base}/annotations/${n}`)}add(n,e,t){return this.http.post(`${this.base}/annotations/${n}`,{author:e,body:t})}remove(n,e){return this.http.delete(`${this.base}/annotations/${n}/${e}`)}static \u0275fac=function(e){return new(e||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})};var Mn=["svg"];function On(i,n){i&1&&(l(0,"div",8),c(1,"No graph data \u2014 changed files have no detectable internal imports."),a())}var Ae=class i{impact=null;svgRef;simulation=null;hasData=!1;ngAfterViewInit(){this.render()}ngOnChanges(){this.render()}ngOnDestroy(){this.simulation?.stop()}render(){if(!this.svgRef)return;let n=this.svgRef.nativeElement,e=on(n);e.selectAll("*").remove();let t=this.impact;if(!t||t.dependencyRipple.length===0&&t.modules.length===0){this.hasData=!1;return}this.hasData=!0;let o=n.clientWidth||600,r=280,m=new Map,h=(p,H,se)=>{let P=m.get(p);return P||(P={id:p,group:H,label:se},m.set(p,P)),P};for(let p of t.files)h(`f:${p}`,"changed",ot(p));for(let p of t.modules)h(`m:${p}`,"module",p);for(let p of t.dependencyRipple)h(`f:${p.from}`,"changed",ot(p.from)),h(`f:${p.to}`,"imported",ot(p.to));let g=[];for(let p of t.dependencyRipple)g.push({source:`f:${p.from}`,target:`f:${p.to}`,type:"imports"});for(let p of t.files){let H=En(p);t.modules.includes(H)&&g.push({source:`f:${p}`,target:`m:${H}`,type:"in-module"})}let d=Array.from(m.values()),w=e.append("g").attr("stroke","var(--border-strong)").attr("stroke-opacity",.5).selectAll("line").data(g).join("line").attr("stroke-dasharray",p=>p.type==="in-module"?"2,3":null),R=e.append("g").selectAll("circle").data(d).join("circle").attr("r",p=>p.group==="module"?7:5).attr("fill",p=>p.group==="changed"?"var(--accent)":p.group==="imported"?"#f59e0b":"#8b5cf6").attr("stroke","var(--bg-app)").attr("stroke-width",1.5).call(ye());R.append("title").text(p=>p.id.slice(2));let Y=e.append("g").selectAll("text").data(d).join("text").attr("class","node-label").attr("dx",8).attr("dy",3).text(p=>p.label);this.simulation?.stop(),this.simulation=cn(d).force("link",ln(g).id(p=>p.id).distance(60).strength(.4)).force("charge",dn().strength(-160)).force("center",an(o/2,r/2)).force("collide",sn(14)).on("tick",()=>{w.attr("x1",p=>p.source.x??0).attr("y1",p=>p.source.y??0).attr("x2",p=>p.target.x??0).attr("y2",p=>p.target.y??0),R.attr("cx",p=>p.x??0).attr("cy",p=>p.y??0),Y.attr("x",p=>p.x??0).attr("y",p=>p.y??0)});function ye(){function p(P,E){P.active||window.__impactSim?.alphaTarget?.(.3).restart(),E.fx=E.x,E.fy=E.y}function H(P,E){E.fx=P.x,E.fy=P.y}function se(P,E){P.active||window.__impactSim?.alphaTarget?.(0),E.fx=null,E.fy=null}return rn().on("start",p).on("drag",H).on("end",se)}window.__impactSim=this.simulation}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-impact-graph"]],viewQuery:function(e,t){if(e&1&&q(Mn,7),e&2){let o;K(o=X())&&(t.svgRef=o.first)}},inputs:{impact:"impact"},features:[ke],decls:11,vars:1,consts:[["svg",""],[1,"legend"],[1,"dot","dot-changed"],[1,"dot","dot-imported"],[1,"dot","dot-module"],[1,"canvas-wrap"],["width","100%","height","280","aria-label","Commit impact graph"],["class","empty",4,"ngIf"],[1,"empty"]],template:function(e,t){e&1&&(l(0,"div",1),b(1,"span",2),c(2," changed "),b(3,"span",3),c(4," imports "),b(5,"span",4),c(6," module "),a(),l(7,"div",5),wt(),b(8,"svg",6,0),v(10,On,2,0,"div",7),a()),e&2&&(s(10),u("ngIf",!t.hasData))},dependencies:[T,I],styles:["[_nghost-%COMP%]{display:block}.legend[_ngcontent-%COMP%]{display:flex;gap:.75rem;align-items:center;font-size:11px;color:var(--fg-muted);margin-bottom:.4rem}.dot[_ngcontent-%COMP%]{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:4px}.dot-changed[_ngcontent-%COMP%]{background:var(--accent)}.dot-imported[_ngcontent-%COMP%]{background:#f59e0b}.dot-module[_ngcontent-%COMP%]{background:#8b5cf6}.canvas-wrap[_ngcontent-%COMP%]{position:relative;background:var(--bg-app);border-radius:var(--radius-sm);border:1px solid var(--border-soft);overflow:hidden}.empty[_ngcontent-%COMP%]{position:absolute;inset:0;display:grid;place-items:center;color:var(--fg-muted);font-size:11px;pointer-events:none}svg[_ngcontent-%COMP%] [_ngcontent-%COMP%]:global(.node-label){font-size:9px;fill:var(--fg-secondary);font-family:var(--font-mono, monospace);pointer-events:none}"],changeDetection:0})};function ot(i){let n=i.split("/");return n[n.length-1]}function En(i){let n=i.split("/");return n.length===1?"(root)":n.slice(0,Math.min(n.length-1,3)).join("/")}function Dn(i,n){if(i&1&&(l(0,"span",36),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function kn(i,n){if(i&1&&(l(0,"span",37),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function Pn(i,n){i&1&&(l(0,"span",38),c(1,"merge"),a())}function Rn(i,n){if(i&1&&(l(0,"pre",39),c(1),a()),i&2){let e=C().ngIf;s(),_(e.body)}}function In(i,n){if(i&1){let e=F();l(0,"div",40)(1,"span",41),c(2,"AI"),a(),l(3,"span",42),c(4),a(),l(5,"button",43),S("click",function(){M(e);let o=C(2);return O(o.explanation.set(null))}),c(6,"\xD7"),a()()}if(i&2){let e=n.ngIf;s(4),_(e)}}function Tn(i,n){if(i&1&&(l(0,"div",44),c(1),a()),i&2){let e=n.ngIf;s(),_(e)}}function Nn(i,n){if(i&1&&(l(0,"li"),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function Vn(i,n){if(i&1){let e=F();l(0,"li",28),S("click",function(){let o=M(e).$implicit,r=C(3);return O(r.state.selectHash(o.hash))}),l(1,"code"),c(2),a(),l(3,"span"),c(4),a()()}if(i&2){let e=n.$implicit;s(2),_(e.hash.slice(0,7)),s(2),_(e.subject)}}function Fn(i,n){if(i&1&&(l(0,"div",45)(1,"div",46)(2,"span"),c(3,"Impact"),a(),l(4,"span",47),c(5),a()(),b(6,"app-impact-graph",48),l(7,"div",49)(8,"div")(9,"h4"),c(10,"Modules"),a(),l(11,"ul",50),v(12,Nn,2,1,"li",51),a()(),l(13,"div")(14,"h4"),c(15,"Related commits"),a(),l(16,"ul",52),v(17,Vn,5,2,"li",53),a()()()()),i&2){let e=n.ngIf;s(5),Bt(" ",e.files.length," files \xB7 ",e.modules.length," modules \xB7 ",e.relatedCommits.length," related commits "),s(),u("impact",e),s(6),u("ngForOf",e.modules),s(5),u("ngForOf",e.relatedCommits)}}function zn(i,n){if(i&1&&(l(0,"span",54),c(1),a()),i&2){let e=C(2);s(),_(e.files().length)}}function Ln(i,n){if(i&1&&(l(0,"span",63),c(1),a()),i&2){let e=C().$implicit;s(),B("+",e.additions)}}function An(i,n){if(i&1&&(l(0,"span",64),c(1),a()),i&2){let e=C().$implicit;s(),B("\u2212",e.deletions)}}function Bn(i,n){if(i&1){let e=F();l(0,"div",55)(1,"button",56),S("click",function(){let o=M(e).$implicit,r=C(2);return O(r.selectFile(o))}),b(2,"span",57),l(3,"span",58),c(4),a(),l(5,"span",59),v(6,Ln,2,1,"span",60)(7,An,2,1,"span",61),a()(),l(8,"button",62),S("click",function(){let o=M(e).$implicit,r=C(2);return O(r.openFileHistory(o.file))}),c(9," \u23F1 "),a()()}if(i&2){let e,t=n.$implicit,o=C(2);s(),z("selected",t.file===((e=o.activeFile())==null?null:e.file)),s(),ge("data-status",t.status),s(),u("title",t.file),s(),_(t.file),s(2),u("ngIf",t.additions),s(),u("ngIf",t.deletions)}}function jn(i,n){i&1&&(l(0,"div",65),c(1," No files changed. "),a())}function Gn(i,n){i&1&&(l(0,"div",65),c(1,"Loading\u2026"),a())}function Hn(i,n){if(i&1){let e=F();l(0,"div",66)(1,"div",67)(2,"strong"),c(3),a(),l(4,"span",68),c(5),he(6,"date"),a(),l(7,"button",69),S("click",function(){let o=M(e).$implicit,r=C(2);return O(r.deleteComment(o.id))}),c(8,"\xD7"),a()(),l(9,"p",70),c(10),a()()}if(i&2){let e=n.$implicit;s(3),_(e.author),s(2),_(_e(6,3,e.createdAt,"short")),s(5),_(e.body)}}function $n(i,n){if(i&1){let e=F();Re(0),l(1,"header",2)(2,"div",3)(3,"span",4),c(4),a(),l(5,"span",5),v(6,Dn,2,1,"span",6)(7,kn,2,1,"span",7)(8,Pn,2,0,"span",8),a()(),l(9,"h2",9),c(10),a(),l(11,"div",10)(12,"span"),c(13),a(),l(14,"span",11),c(15,"\u2022"),a(),l(16,"span"),c(17),he(18,"date"),a()(),v(19,Rn,2,1,"pre",12),l(20,"div",13)(21,"button",14),S("click",function(){M(e);let o=C();return O(o.onExplain())}),c(22),a(),l(23,"button",14),S("click",function(){M(e);let o=C();return O(o.onLoadImpact())}),c(24),a(),l(25,"button",15),S("click",function(){M(e);let o=C();return O(o.copyShareLink())}),c(26),a()(),v(27,In,7,1,"div",16)(28,Tn,2,1,"div",17),a(),v(29,Fn,18,6,"div",18),l(30,"div",19)(31,"aside",20)(32,"div",21)(33,"span"),c(34,"Files"),a(),v(35,zn,2,1,"span",22),a(),l(36,"div",23),v(37,Bn,10,7,"div",24)(38,jn,2,0,"div",25)(39,Gn,2,0,"div",25),a()(),l(40,"section",26)(41,"details",27)(42,"summary",28),S("click",function(o){M(e);let r=C();return O(r.toggleAnnotations(o))}),c(43),a(),l(44,"div",29),v(45,Hn,11,6,"div",30),l(46,"div",31)(47,"input",32),it("ngModelChange",function(o){M(e);let r=C();return nt(r.commentAuthor,o)||(r.commentAuthor=o),O(o)}),a(),l(48,"textarea",33),it("ngModelChange",function(o){M(e);let r=C();return nt(r.commentDraft,o)||(r.commentDraft=o),O(o)}),a(),l(49,"button",34),S("click",function(){M(e);let o=C();return O(o.addComment())}),c(50,"Post"),a()()()(),b(51,"app-diff-viewer",35),a()(),Ie()}if(i&2){let e=n.ngIf,t=C();s(4),_(e.shortHash),s(2),u("ngForOf",e.tags),s(),u("ngForOf",e.branches),s(),u("ngIf",e.isMerge),s(2),_(e.subject),s(3),Ne("",e.author," <",e.authorEmail,">"),s(4),_(_e(18,29,e.date,"medium")),s(2),u("ngIf",e.body),s(2),u("disabled",t.explaining()),s(),B(" ",t.explaining()?"...":"\u2728 Explain change"," "),s(),u("disabled",t.loadingImpact()),s(),B(" ",t.loadingImpact()?"...":t.impact()?"Refresh impact":"Show impact"," "),s(2),B(" ",t.shareCopied()?"Copied!":"\u{1F517} Share"," "),s(),u("ngIf",t.explanation()),s(),u("ngIf",t.explainError()),s(),u("ngIf",t.impact()),s(6),u("ngIf",t.files().length),s(2),u("ngForOf",t.files())("ngForTrackBy",t.trackByFile),s(),u("ngIf",!t.files().length&&!t.loading()),s(),u("ngIf",t.loading()),s(2),u("open",t.annotationsOpen()),s(2),B(" \u{1F4AC} Notes (",t.comments().length,") "),s(2),u("ngForOf",t.comments()),s(2),tt("ngModel",t.commentAuthor),s(),tt("ngModel",t.commentDraft),s(),u("disabled",!t.commentDraft.trim()),s(2),u("fileInput",t.activeFile())}}function Wn(i,n){i&1&&(l(0,"div",71)(1,"p",72),c(2,"No commit selected"),a(),l(3,"p",73),c(4," Pick a commit from the list, or press "),l(5,"kbd",74),c(6,"\u2318K"),a(),c(7," to open the command palette. "),a()())}var Be=class i{state=f(G);git=f(en);insightsApi=f(tn);annotationsApi=f(Le);router=f(Yt);commit=this.state.selected;impact=x(null);loadingImpact=x(!1);explanation=x(null);explainError=x(null);explaining=x(!1);comments=x([]);annotationsOpen=x(!1);shareCopied=x(!1);commentDraft="";commentAuthor="me";loading=x(!1);files=Jt(Xt(this.commit).pipe(Oe(n=>n?(this.loading.set(!0),this.git.getDiff(n.hash).pipe(_t(()=>W([])))):(this.loading.set(!1),W([])))),{initialValue:[]});activeFileIndex=x(0);activeFile=ee(()=>{let n=this.files();if(!n.length)return null;let e=Math.min(this.activeFileIndex(),n.length-1);return n[e]});constructor(){j(()=>{this.files(),this.activeFileIndex.set(0),this.loading.set(!1)}),j(()=>{let n=this.commit();if(this.impact.set(null),this.explanation.set(null),this.explainError.set(null),this.shareCopied.set(!1),!n){this.comments.set([]);return}this.annotationsApi.list(n.hash).subscribe({next:e=>this.comments.set(e),error:()=>this.comments.set([])})})}trackByFile(n,e){return e.file}selectFile(n){let e=this.files().findIndex(t=>t.file===n.file);e>=0&&this.activeFileIndex.set(e)}openFileHistory(n){this.router.navigate(["/file",encodeURIComponent(n)])}shortPath(n){if(n.length<=32)return n;let e=n.split("/");return e.length<=2?n:e[0]+"/.../"+e.slice(-2).join("/")}onLoadImpact(){let n=this.commit();n&&(this.loadingImpact.set(!0),this.insightsApi.impact(n.hash).subscribe({next:e=>{this.impact.set(e),this.loadingImpact.set(!1)},error:()=>this.loadingImpact.set(!1)}))}onExplain(){let n=this.commit();!n||this.explaining()||(this.explaining.set(!0),this.explainError.set(null),this.insightsApi.explainCommit(n.hash).subscribe({next:e=>{this.explanation.set(e.summary),this.explaining.set(!1)},error:e=>{this.explainError.set(e?.error?.error??"AI explanation unavailable. Set ANTHROPIC_API_KEY or OPENAI_API_KEY."),this.explaining.set(!1)}}))}copyShareLink(){let n=this.commit();if(!n)return;let e=`${window.location.origin}/?commit=${n.hash}`;navigator.clipboard?.writeText(e).then(()=>{this.shareCopied.set(!0),setTimeout(()=>this.shareCopied.set(!1),1500)}).catch(()=>{this.shareCopied.set(!1)})}toggleAnnotations(n){setTimeout(()=>this.annotationsOpen.set(!this.annotationsOpen()),0)}addComment(){let n=this.commit();!n||!this.commentDraft.trim()||this.annotationsApi.add(n.hash,this.commentAuthor||"anonymous",this.commentDraft.trim()).subscribe({next:e=>{this.comments.set([...this.comments(),e]),this.commentDraft=""}})}deleteComment(n){let e=this.commit();e&&this.annotationsApi.remove(e.hash,n).subscribe({next:()=>this.comments.set(this.comments().filter(t=>t.id!==n))})}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-commit-detail"]],decls:3,vars:2,consts:[["empty",""],[4,"ngIf","ngIfElse"],[1,"head"],[1,"row"],[1,"hash"],[1,"badges"],["class","badge tag",4,"ngFor","ngForOf"],["class","badge branch",4,"ngFor","ngForOf"],["class","badge merge",4,"ngIf"],[1,"subject"],[1,"meta"],[1,"dot"],["class","body",4,"ngIf"],[1,"actions"],[1,"btn","btn-ghost","btn-sm",3,"click","disabled"],[1,"btn","btn-ghost","btn-sm",3,"click"],["class","ai-card",4,"ngIf"],["class","ai-card error",4,"ngIf"],["class","impact-card",4,"ngIf"],[1,"split"],[1,"files"],[1,"files-header"],["class","count",4,"ngIf"],[1,"files-list"],["class","file-row",4,"ngFor","ngForOf","ngForTrackBy"],["class","files-empty",4,"ngIf"],[1,"diff"],[1,"annotations",3,"open"],[3,"click"],[1,"annot-body"],["class","comment",4,"ngFor","ngForOf"],[1,"comment-form"],["placeholder","Your name",1,"input",3,"ngModelChange","ngModel"],["placeholder","Add a note for your team\u2026",1,"input",3,"ngModelChange","ngModel"],[1,"btn",3,"click","disabled"],[3,"fileInput"],[1,"badge","tag"],[1,"badge","branch"],[1,"badge","merge"],[1,"body"],[1,"ai-card"],[1,"ai-pill"],[1,"ai-text"],[1,"btn","btn-ghost","btn-icon","close",3,"click"],[1,"ai-card","error"],[1,"impact-card"],[1,"impact-head"],[1,"impact-meta"],[3,"impact"],[1,"impact-body"],[1,"modules"],[4,"ngFor","ngForOf"],[1,"related"],[3,"click",4,"ngFor","ngForOf"],[1,"count"],[1,"file-row"],[1,"file",3,"click"],[1,"status-dot"],[1,"path",3,"title"],[1,"counts"],["class","add",4,"ngIf"],["class","del",4,"ngIf"],["title","View file history",1,"file-history",3,"click"],[1,"add"],[1,"del"],[1,"files-empty"],[1,"comment"],[1,"comment-head"],[1,"comment-date"],["title","Delete",1,"btn","btn-ghost","btn-icon",3,"click"],[1,"comment-body"],[1,"placeholder"],[1,"title"],[1,"hint"],[1,"kbd"]],template:function(e,t){if(e&1&&v(0,$n,52,32,"ng-container",1)(1,Wn,8,0,"ng-template",null,0,Ve),e&2){let o=Te(2);u("ngIf",t.commit())("ngIfElse",o)}},dependencies:[T,U,I,Kt,Zt,Qt,qt,nn,Ae,Fe],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg-app)}.head[_ngcontent-%COMP%]{padding:.85rem 1rem;border-bottom:1px solid var(--border-soft);background:var(--bg-surface)}.row[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin-bottom:.4rem}.hash[_ngcontent-%COMP%]{font-family:var(--font-mono);font-size:12px;color:var(--fg-muted);padding:2px 6px;background:var(--bg-surface-2);border:1px solid var(--border-soft);border-radius:4px}.badges[_ngcontent-%COMP%]{display:flex;flex-wrap:wrap;gap:4px}.badge[_ngcontent-%COMP%]{font-size:10px;font-weight:600;padding:2px 6px;border-radius:999px}.badge.tag[_ngcontent-%COMP%]{background:#d9770626;color:var(--warning)}.badge.branch[_ngcontent-%COMP%]{background:var(--accent-soft);color:var(--accent)}.badge.merge[_ngcontent-%COMP%]{background:#8b5cf62e;color:#8b5cf6}.subject[_ngcontent-%COMP%]{font-size:18px;margin:0 0 4px;font-weight:600}.meta[_ngcontent-%COMP%]{display:flex;gap:6px;align-items:center;font-size:12px;color:var(--fg-muted)}.meta[_ngcontent-%COMP%] .dot[_ngcontent-%COMP%]{opacity:.5}.body[_ngcontent-%COMP%]{white-space:pre-wrap;font-family:var(--font-mono);font-size:12px;color:var(--fg-secondary);background:var(--bg-surface-2);border:1px solid var(--border-soft);border-radius:var(--radius-sm);padding:.5rem .75rem;margin-top:.5rem;max-height:160px;overflow:auto}.split[_ngcontent-%COMP%]{flex:1;display:grid;grid-template-columns:280px 1fr;grid-template-rows:minmax(0,1fr);min-height:0;overflow:hidden}.files[_ngcontent-%COMP%]{display:flex;flex-direction:column;min-height:0;background:var(--bg-surface);border-right:1px solid var(--border-soft)}.files-header[_ngcontent-%COMP%]{display:flex;justify-content:space-between;padding:.5rem .85rem;font-size:12px;color:var(--fg-muted);border-bottom:1px solid var(--border-soft)}.count[_ngcontent-%COMP%]{background:var(--bg-surface-2);padding:0 6px;border-radius:999px;font-size:11px}.files-list[_ngcontent-%COMP%]{overflow:auto;flex:1;min-height:0}.file[_ngcontent-%COMP%]{display:grid;grid-template-columns:10px 1fr auto;gap:.5rem;align-items:center;width:100%;padding:.5rem .85rem;border:0;background:transparent;color:inherit;cursor:pointer;text-align:left;border-bottom:1px solid var(--border-soft);font-size:12px}.file[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.file.selected[_ngcontent-%COMP%]{background:var(--bg-selected)}.file[_ngcontent-%COMP%] .path[_ngcontent-%COMP%]{font-family:var(--font-mono);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;direction:rtl;text-align:left}.status-dot[_ngcontent-%COMP%]{width:8px;height:8px;border-radius:50%;background:var(--accent)}.status-dot[data-status=added][_ngcontent-%COMP%]{background:var(--success)}.status-dot[data-status=deleted][_ngcontent-%COMP%]{background:var(--danger)}.status-dot[data-status=renamed][_ngcontent-%COMP%], .status-dot[data-status=copied][_ngcontent-%COMP%]{background:var(--warning)}.status-dot[data-status=binary][_ngcontent-%COMP%]{background:var(--fg-muted)}.counts[_ngcontent-%COMP%]{display:flex;gap:6px;font-family:var(--font-mono);font-size:11px}.counts[_ngcontent-%COMP%] .add[_ngcontent-%COMP%]{color:var(--success)}.counts[_ngcontent-%COMP%] .del[_ngcontent-%COMP%]{color:var(--danger)}.files-empty[_ngcontent-%COMP%]{padding:1rem;color:var(--fg-muted);font-size:12px;text-align:center}.diff[_ngcontent-%COMP%]{min-width:0;min-height:0;display:flex;flex-direction:column;overflow:hidden}.placeholder[_ngcontent-%COMP%]{flex:1;display:grid;place-items:center;text-align:center;color:var(--fg-muted)}.placeholder[_ngcontent-%COMP%] .title[_ngcontent-%COMP%]{font-size:16px;margin-bottom:4px;color:var(--fg-secondary)}.placeholder[_ngcontent-%COMP%] .hint[_ngcontent-%COMP%]{font-size:13px}.actions[_ngcontent-%COMP%]{display:flex;flex-wrap:wrap;gap:.4rem;margin-top:.6rem}.btn-sm[_ngcontent-%COMP%]{font-size:11px;padding:.3rem .65rem}.ai-card[_ngcontent-%COMP%]{display:flex;align-items:flex-start;gap:.5rem;padding:.55rem .75rem;margin-top:.5rem;background:color-mix(in oklab,var(--accent) 12%,transparent);border-radius:var(--radius-sm);font-size:12px;color:var(--fg-secondary)}.ai-card.error[_ngcontent-%COMP%]{background:#ef44441f;color:var(--danger)}.ai-pill[_ngcontent-%COMP%]{flex-shrink:0;font-size:10px;font-weight:700;letter-spacing:.04em;background:var(--accent);color:var(--accent-fg);padding:1px 5px;border-radius:4px}.ai-text[_ngcontent-%COMP%]{flex:1;line-height:1.5}.ai-card[_ngcontent-%COMP%] .close[_ngcontent-%COMP%]{font-size:14px;line-height:1;padding:0 6px}.impact-card[_ngcontent-%COMP%]{margin:.6rem 1rem;background:var(--bg-surface);border:1px solid var(--border-soft);border-radius:var(--radius-md);padding:.75rem 1rem}.impact-head[_ngcontent-%COMP%]{display:flex;justify-content:space-between;font-weight:600;margin-bottom:.5rem;font-size:13px}.impact-meta[_ngcontent-%COMP%]{color:var(--fg-muted);font-weight:400;font-size:11px}.impact-body[_ngcontent-%COMP%]{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:.75rem;font-size:12px}.impact-body[_ngcontent-%COMP%] h4[_ngcontent-%COMP%]{margin:0 0 .4rem;font-size:11px;color:var(--fg-muted);text-transform:uppercase;letter-spacing:.04em}.impact-body[_ngcontent-%COMP%] ul[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0}.impact-body[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{padding:2px 0;word-break:break-all}.modules[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace)}.ripple[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-secondary)}.related[_ngcontent-%COMP%] li[_ngcontent-%COMP%]{cursor:pointer;display:flex;gap:.4rem}.related[_ngcontent-%COMP%] li[_ngcontent-%COMP%]:hover{color:var(--accent)}.related[_ngcontent-%COMP%] code[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);color:var(--fg-muted);flex-shrink:0}.impact-body[_ngcontent-%COMP%] .muted[_ngcontent-%COMP%]{color:var(--fg-muted);font-style:italic;margin:0;font-size:11px}.file-row[_ngcontent-%COMP%]{display:flex}.file-row[_ngcontent-%COMP%] .file[_ngcontent-%COMP%]{flex:1}.file-history[_ngcontent-%COMP%]{background:transparent;border:0;border-bottom:1px solid var(--border-soft);cursor:pointer;color:var(--fg-muted);padding:0 .6rem;font-size:12px}.file-history[_ngcontent-%COMP%]:hover{background:var(--bg-elevated);color:var(--accent)}.annotations[_ngcontent-%COMP%]{margin:.5rem;background:var(--bg-surface);border:1px solid var(--border-soft);border-radius:var(--radius-sm)}.annotations[_ngcontent-%COMP%] summary[_ngcontent-%COMP%]{padding:.4rem .7rem;cursor:pointer;font-size:12px;color:var(--fg-secondary);-webkit-user-select:none;user-select:none}.annotations[open][_ngcontent-%COMP%] summary[_ngcontent-%COMP%]{border-bottom:1px solid var(--border-soft)}.annot-body[_ngcontent-%COMP%]{padding:.5rem .7rem}.comment[_ngcontent-%COMP%]{padding:.4rem 0;border-bottom:1px dashed var(--border-soft);font-size:12px}.comment[_ngcontent-%COMP%]:last-of-type{border-bottom:0}.comment-head[_ngcontent-%COMP%]{display:flex;align-items:center;gap:.5rem}.comment-date[_ngcontent-%COMP%]{color:var(--fg-muted);font-size:11px;flex:1}.comment-body[_ngcontent-%COMP%]{margin:.2rem 0 0;line-height:1.4;white-space:pre-wrap}.comment-form[_ngcontent-%COMP%]{display:flex;gap:.4rem;flex-direction:column;margin-top:.5rem}.comment-form[_ngcontent-%COMP%] .input[_ngcontent-%COMP%]{width:100%;padding:.35rem .5rem;background:var(--bg-app);border:1px solid var(--border-soft);border-radius:var(--radius-sm);color:var(--fg-primary);font-family:inherit;font-size:12px}.comment-form[_ngcontent-%COMP%] textarea[_ngcontent-%COMP%]{min-height:60px;resize:vertical}.comment-form[_ngcontent-%COMP%] .btn[_ngcontent-%COMP%]{align-self:flex-end}"],changeDetection:0})};var Un=["canvas"],Yn=["scroll"];function Zn(i,n){if(i&1&&b(0,"span",11),i&2){let e=n.$implicit;J("background",e)}}function Qn(i,n){i&1&&(l(0,"div",12),c(1," No commits to draw. "),a())}var k=34,xe=24,je=5.5,rt=16,re=16,at=["#4f46e5","#06b6d4","#f59e0b","#ef4444","#10b981","#8b5cf6","#ec4899","#0ea5e9"],Ge=class i{state=f(G);theme=f(mn);legendColors=at.slice(0,5);graphSummary=ee(()=>{let n=this.state.commits().length,e=this.laneCount;return n?`${n.toLocaleString()} commits across ${e} lane${e===1?"":"s"}`:"Swim-lane visualization"});contentHeight=ee(()=>{let n=this.state.commits().length;return n?re*2+n*k:0});canvasRef;scrollRef;nodes=[];rowByHash=new Map;laneCount=1;hoverRow=-1;onCanvasClick=n=>this.onClick(n);onCanvasMove=n=>this.onMouseMove(n);onCanvasLeave=()=>this.onMouseLeave();scrollRaf=0;onScroll=()=>{this.scrollRaf||(this.scrollRaf=requestAnimationFrame(()=>{this.scrollRaf=0,this.draw()}))};constructor(){j(()=>{this.layout(this.state.commits()),this.draw()}),j(()=>{this.state.selectedHash(),this.theme.resolved(),this.draw()})}ngAfterViewInit(){let n=this.canvasRef.nativeElement;n.addEventListener("click",this.onCanvasClick),n.addEventListener("mousemove",this.onCanvasMove),n.addEventListener("mouseleave",this.onCanvasLeave),this.scrollRef?.nativeElement.addEventListener("scroll",this.onScroll,{passive:!0}),this.draw()}ngOnDestroy(){let n=this.canvasRef?.nativeElement;n?.removeEventListener("click",this.onCanvasClick),n?.removeEventListener("mousemove",this.onCanvasMove),n?.removeEventListener("mouseleave",this.onCanvasLeave),this.scrollRef?.nativeElement.removeEventListener("scroll",this.onScroll),this.scrollRaf&&cancelAnimationFrame(this.scrollRaf)}onResize(){this.draw()}layout(n){if(this.nodes=[],this.rowByHash.clear(),this.hoverRow=-1,!n.length){this.laneCount=1;return}let e=[],t=o=>{let r=e.indexOf(o);if(r>=0)return r;let m=e.indexOf(null);return m>=0?(e[m]=o,m):(e.push(o),e.length-1)};for(let o=0;o<n.length;o++){let r=n[o],m=t(r.hash),h={commit:r,row:o,lane:m};this.nodes.push(h),this.rowByHash.set(r.hash,h);let[g,...d]=r.parents;e[m]=g??null;for(let w of d)if(e.indexOf(w)===-1){let R=e.indexOf(null);R>=0?e[R]=w:e.push(w)}for(;e.length&&e[e.length-1]===null;)e.pop()}this.laneCount=Math.max(1,this.nodes.reduce((o,r)=>Math.max(o,r.lane+1),0))}draw(){let n=this.canvasRef?.nativeElement;if(!n)return;let e=this.scrollRef?.nativeElement,t=window.devicePixelRatio||1,o=rt*2+this.laneCount*xe,r=e?.scrollTop??0,m=e?.clientHeight??0,h=Math.max(o,e?.clientWidth??o),g=Math.max(m||k*8,k);n.width=Math.floor(h*t),n.height=Math.floor(g*t),n.style.width=`${h}px`,n.style.height=`${g}px`,n.style.transform=`translateY(${r}px)`;let d=n.getContext("2d"),w=this.readTheme(n);if(d.setTransform(t,0,0,t,0,-r*t),d.clearRect(0,r,h,g),d.fillStyle=w.surface,d.fillRect(0,r,h,g),!this.nodes.length)return;let R=y=>rt+y*xe+xe/2,Y=y=>re+y*k+k/2,ye=y=>at[y%at.length],p=this.state.selectedHash(),H=k*4,se=Math.max(0,Math.floor((r-re-H)/k)),P=Math.min(this.nodes.length-1,Math.ceil((r+g-re+H)/k)),E=this.nodes.slice(se,P+1);this.drawRows(d,h,R,Y,w,p,E),this.drawGuides(d,Y,w),d.lineCap="round",d.lineJoin="round";for(let y of E)for(let le of y.commit.parents){let $=this.rowByHash.get(le);if(!$)continue;let ne=R(y.lane),Z=Y(y.row),ce=R($.lane),ie=Y($.row);d.strokeStyle=w.shadow,d.lineWidth=4,d.globalAlpha=.35,this.drawEdge(d,ne,Z,ce,ie),d.strokeStyle=ye($.lane),d.lineWidth=y.commit.isMerge?2.6:2.2,d.globalAlpha=p&&p!==y.commit.hash&&p!==$.commit.hash?.55:.9,this.drawEdge(d,ne,Z,ce,ie),d.globalAlpha=1}for(let y of E){let le=R(y.lane),$=Y(y.row),ne=ye(y.lane),Z=y.commit.hash===p,ce=y.row===this.hoverRow,ie=Z?je+2:ce?je+1:je;d.beginPath(),d.arc(le,$,ie+3,0,Math.PI*2),d.fillStyle=w.nodeRing,d.fill(),d.beginPath(),d.arc(le,$,ie,0,Math.PI*2),d.fillStyle=y.commit.isMerge?w.surface:ne,d.fill(),d.lineWidth=y.commit.isMerge||Z?2.5:1.75,d.strokeStyle=ne,d.stroke(),(Z||ce)&&(d.beginPath(),d.arc(le,$,ie+5,0,Math.PI*2),d.strokeStyle=ne,d.globalAlpha=Z?.42:.24,d.lineWidth=2,d.stroke(),d.globalAlpha=1)}}drawRows(n,e,t,o,r,m,h=this.nodes){for(let g of h){let d=o(g.row)-k/2;if(g.row%2===1&&(n.fillStyle=r.rowAlt,n.fillRect(0,d,e,k)),(g.row===this.hoverRow||g.commit.hash===m)&&(n.fillStyle=g.commit.hash===m?r.rowSelected:r.rowHover,this.roundRect(n,6,d+3,e-12,k-6,8),n.fill()),g.commit.branches.length||g.commit.tags.length){let w=t(g.lane)+je+8;this.drawRefPill(n,w,o(g.row),g.commit,r)}}}drawGuides(n,e,t){n.save(),n.strokeStyle=t.guide,n.lineWidth=1,n.setLineDash([3,5]);for(let o=0;o<this.laneCount;o++){let r=rt+o*xe+xe/2;n.beginPath(),n.moveTo(r,re/2),n.lineTo(r,e(this.nodes.length-1)+k/2),n.stroke()}n.restore()}drawEdge(n,e,t,o,r){if(n.beginPath(),n.moveTo(e,t),e===o)n.lineTo(o,r);else{let m=t+Math.min(k*.75,Math.max(12,(r-t)*.36));n.bezierCurveTo(e,m,o,m,o,r)}n.stroke()}drawRefPill(n,e,t,o,r){let m=o.tags[0]??o.branches[0];if(!m)return;let h=m.length>16?`${m.slice(0,15)}...`:m;n.font="600 10px ui-sans-serif, system-ui, sans-serif";let g=Math.min(96,n.measureText(h).width+14),d=18;n.fillStyle=o.tags.length?r.warningSoft:r.accentSoft,this.roundRect(n,e,t-d/2,g,d,999),n.fill(),n.fillStyle=o.tags.length?r.warning:r.accent,n.fillText(h,e+7,t+3.5)}onClick(n){let e=this.nodeFromEvent(n);e&&this.state.selectHash(e.commit.hash)}onMouseMove(n){let e=this.nodeFromEvent(n),t=e?.row??-1;t!==this.hoverRow&&(this.hoverRow=t,this.canvasRef.nativeElement.style.cursor=e?"pointer":"default",this.draw())}onMouseLeave(){this.hoverRow!==-1&&(this.hoverRow=-1,this.canvasRef.nativeElement.style.cursor="default",this.draw())}nodeFromEvent(n){let e=this.scrollRef?.nativeElement,t=e?.getBoundingClientRect();if(!t)return;let o=n.clientY-t.top+(e?.scrollTop??0),r=Math.floor((o-re)/k);return this.nodes[r]}readTheme(n){let e=getComputedStyle(n);return{accent:this.css(e,"--accent","#4f46e5"),accentSoft:this.css(e,"--accent-soft","#eef2ff"),guide:this.css(e,"--graph-guide","rgba(148, 163, 184, 0.28)"),nodeRing:this.css(e,"--graph-node-ring","#ffffff"),rowAlt:this.css(e,"--graph-row-alt","rgba(15, 23, 42, 0.025)"),rowHover:this.css(e,"--graph-row-hover","rgba(79, 70, 229, 0.08)"),rowSelected:this.css(e,"--graph-row-selected","rgba(79, 70, 229, 0.14)"),shadow:this.css(e,"--graph-shadow","rgba(15, 23, 42, 0.12)"),surface:this.css(e,"--bg-surface","#ffffff"),warning:this.css(e,"--warning","#d97706"),warningSoft:"rgba(217, 119, 6, 0.15)"}}css(n,e,t){return n.getPropertyValue(e).trim()||t}roundRect(n,e,t,o,r,m){let h=Math.min(m,o/2,r/2);n.beginPath(),n.moveTo(e+h,t),n.arcTo(e+o,t,e+o,t+r,h),n.arcTo(e+o,t+r,e,t+r,h),n.arcTo(e,t+r,e,t,h),n.arcTo(e,t,e+o,t,h),n.closePath()}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-commit-graph"]],viewQuery:function(e,t){if(e&1&&(q(Un,7),q(Yn,7)),e&2){let o;K(o=X())&&(t.canvasRef=o.first),K(o=X())&&(t.scrollRef=o.first)}},hostBindings:function(e,t){e&1&&S("resize",function(){return t.onResize()},Pe)},decls:14,vars:5,consts:[["scroll",""],["canvas",""],[1,"header"],[1,"title"],[1,"hint"],["aria-hidden","true",1,"legend"],["class","swatch",3,"background",4,"ngFor","ngForOf"],[1,"scroll"],[1,"phantom"],["aria-label","Commit graph","role","img"],["class","empty",4,"ngIf"],[1,"swatch"],[1,"empty"]],template:function(e,t){e&1&&(l(0,"div",2)(1,"div",3)(2,"span"),c(3,"Graph"),a(),l(4,"span",4),c(5),a()(),l(6,"div",5),v(7,Zn,1,2,"span",6),a()(),l(8,"div",7,0),b(10,"div",8)(11,"canvas",9,1),v(13,Qn,2,0,"div",10),a()),e&2&&(s(5),_(t.graphSummary()),s(2),u("ngForOf",t.legendColors),s(3),J("height",t.contentHeight(),"px"),s(3),u("ngIf",!t.state.commits().length&&!t.state.loading()))},dependencies:[T,U,I],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg-surface);border-right:1px solid var(--border-soft)}.header[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:space-between;gap:.75rem;padding:.6rem .85rem;border-bottom:1px solid var(--border-soft);font-size:12px;color:var(--fg-muted);background:color-mix(in oklab,var(--bg-surface) 96%,var(--bg-surface-2))}.title[_ngcontent-%COMP%]{display:flex;flex-direction:column;gap:1px;min-width:0}.title[_ngcontent-%COMP%] > span[_ngcontent-%COMP%]:first-child{color:var(--fg-primary);font-size:13px;font-weight:600}.hint[_ngcontent-%COMP%]{white-space:nowrap}.legend[_ngcontent-%COMP%]{display:flex;gap:4px;align-items:center;flex:0 0 auto}.swatch[_ngcontent-%COMP%]{width:8px;height:8px;border-radius:999px;box-shadow:0 0 0 2px var(--bg-surface)}.scroll[_ngcontent-%COMP%]{position:relative;flex:1;overflow:auto;min-height:0;background:radial-gradient(circle at 24px 24px,var(--graph-row-alt) 0 1px,transparent 1px 100%),var(--bg-surface);background-size:24px 24px}.phantom[_ngcontent-%COMP%]{width:1px;pointer-events:none}canvas[_ngcontent-%COMP%]{display:block;position:absolute;top:0;left:0;pointer-events:auto;will-change:transform}.empty[_ngcontent-%COMP%]{position:absolute;inset:0;display:grid;place-items:center;padding:1rem;color:var(--fg-muted);font-size:12px;text-align:center}"],changeDetection:0})};function be(i,n=0){return qn(i)?Number(i):arguments.length===2?n:0}function qn(i){return!isNaN(parseFloat(i))&&!isNaN(Number(i))}function pn(i){return i instanceof me?i.nativeElement:i}var st;try{st=typeof Intl<"u"&&Intl.v8BreakIterator}catch{st=!1}var He=(()=>{class i{_platformId=f(Et);isBrowser=this._platformId?Wt(this._platformId):typeof document=="object"&&!!document;EDGE=this.isBrowser&&/(edge)/i.test(navigator.userAgent);TRIDENT=this.isBrowser&&/(msie|trident)/i.test(navigator.userAgent);BLINK=this.isBrowser&&!!(window.chrome||st)&&typeof CSS<"u"&&!this.EDGE&&!this.TRIDENT;WEBKIT=this.isBrowser&&/AppleWebKit/i.test(navigator.userAgent)&&!this.BLINK&&!this.EDGE&&!this.TRIDENT;IOS=this.isBrowser&&/iPad|iPhone|iPod/.test(navigator.userAgent)&&!("MSStream"in window);FIREFOX=this.isBrowser&&/(firefox|minefield)/i.test(navigator.userAgent);ANDROID=this.isBrowser&&/android/i.test(navigator.userAgent)&&!this.TRIDENT;SAFARI=this.isBrowser&&/safari/i.test(navigator.userAgent)&&this.WEBKIT;constructor(){}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();var Kn=new Q("cdk-dir-doc",{providedIn:"root",factory:Xn});function Xn(){return f(De)}var Jn=/^(ar|ckb|dv|he|iw|fa|nqo|ps|sd|ug|ur|yi|.*[-_](Adlm|Arab|Hebr|Nkoo|Rohg|Thaa))(?!.*[-_](Latn|Cyrl)($|-|_))($|-|_)/i;function ei(i){let n=i?.toLowerCase()||"";return n==="auto"&&typeof navigator<"u"&&navigator?.language?Jn.test(navigator.language)?"rtl":"ltr":n==="rtl"?"rtl":"ltr"}var fn=(()=>{class i{get value(){return this.valueSignal()}valueSignal=x("ltr");change=new Rt;constructor(){let e=f(Kn,{optional:!0});if(e){let t=e.body?e.body.dir:null,o=e.documentElement?e.documentElement.dir:null;this.valueSignal.set(ei(t||o||"ltr"))}}ngOnDestroy(){this.change.complete()}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})();var A=(function(i){return i[i.NORMAL=0]="NORMAL",i[i.NEGATED=1]="NEGATED",i[i.INVERTED=2]="INVERTED",i})(A||{}),$e,te;function gn(){if(te==null){if(typeof document!="object"||!document||typeof Element!="function"||!Element)return te=!1,te;if(document.documentElement?.style&&"scrollBehavior"in document.documentElement.style)te=!0;else{let i=Element.prototype.scrollTo;i?te=!/\{\s*\[native code\]\s*\}/.test(i.toString()):te=!1}}return te}function ae(){if(typeof document!="object"||!document)return A.NORMAL;if($e==null){let i=document.createElement("div"),n=i.style;i.dir="rtl",n.width="1px",n.overflow="auto",n.visibility="hidden",n.pointerEvents="none",n.position="absolute";let e=document.createElement("div"),t=e.style;t.width="2px",t.height="1px",i.appendChild(e),document.body.appendChild(i),$e=A.NORMAL,i.scrollLeft===0&&(i.scrollLeft=1,$e=i.scrollLeft===0?A.NEGATED:A.INVERTED),i.remove()}return $e}var lt=(()=>{class i{static \u0275fac=function(t){return new(t||i)};static \u0275mod=pe({type:i});static \u0275inj=de({})}return i})();var We=class{};function un(i){return i&&typeof i.connect=="function"&&!(i instanceof ft)}var Ue=class extends We{_data;constructor(n){super(),this._data=n}connect(){return Se(this._data)?this._data:W(this._data)}disconnect(){}},we=(function(i){return i[i.REPLACED=0]="REPLACED",i[i.INSERTED=1]="INSERTED",i[i.MOVED=2]="MOVED",i[i.REMOVED=3]="REMOVED",i})(we||{}),ct=new Q("_ViewRepeater"),Ye=class{viewCacheSize=20;_viewCache=[];applyChanges(n,e,t,o,r){n.forEachOperation((m,h,g)=>{let d,w;if(m.previousIndex==null){let R=()=>t(m,h,g);d=this._insertView(R,g,e,o(m)),w=d?we.INSERTED:we.REPLACED}else g==null?(this._detachAndCacheView(h,e),w=we.REMOVED):(d=this._moveView(h,g,e,o(m)),w=we.MOVED);r&&r({context:d?.context,operation:w,record:m})})}detach(){for(let n of this._viewCache)n.destroy();this._viewCache=[]}_insertView(n,e,t,o){let r=this._insertViewFromCache(e,t);if(r){r.context.$implicit=o;return}let m=n();return t.createEmbeddedView(m.templateRef,m.context,m.index)}_detachAndCacheView(n,e){let t=e.detach(n);this._maybeCacheView(t,e)}_moveView(n,e,t,o){let r=t.get(n);return t.move(r,e),r.context.$implicit=o,r}_maybeCacheView(n,e){if(this._viewCache.length<this.viewCacheSize)this._viewCache.push(n);else{let t=e.indexOf(n);t===-1?n.destroy():e.remove(t)}}_insertViewFromCache(n,e){let t=this._viewCache.pop();return t&&e.insert(t,n),t||null}};var ti=["contentWrapper"],ni=["*"],Cn=new Q("VIRTUAL_SCROLL_STRATEGY"),dt=class{_scrolledIndexChange=new N;scrolledIndexChange=this._scrolledIndexChange.pipe(vt());_viewport=null;_itemSize;_minBufferPx;_maxBufferPx;constructor(n,e,t){this._itemSize=n,this._minBufferPx=e,this._maxBufferPx=t}attach(n){this._viewport=n,this._updateTotalContentSize(),this._updateRenderedRange()}detach(){this._scrolledIndexChange.complete(),this._viewport=null}updateItemAndBufferSize(n,e,t){t<e,this._itemSize=n,this._minBufferPx=e,this._maxBufferPx=t,this._updateTotalContentSize(),this._updateRenderedRange()}onContentScrolled(){this._updateRenderedRange()}onDataLengthChanged(){this._updateTotalContentSize(),this._updateRenderedRange()}onContentRendered(){}onRenderedOffsetChanged(){}scrollToIndex(n,e){this._viewport&&this._viewport.scrollToOffset(n*this._itemSize,e)}_updateTotalContentSize(){this._viewport&&this._viewport.setTotalContentSize(this._viewport.getDataLength()*this._itemSize)}_updateRenderedRange(){if(!this._viewport)return;let n=this._viewport.getRenderedRange(),e={start:n.start,end:n.end},t=this._viewport.getViewportSize(),o=this._viewport.getDataLength(),r=this._viewport.measureScrollOffset(),m=this._itemSize>0?r/this._itemSize:0;if(e.end>o){let g=Math.ceil(t/this._itemSize),d=Math.max(0,Math.min(m,o-g));m!=d&&(m=d,r=d*this._itemSize,e.start=Math.floor(m)),e.end=Math.max(0,Math.min(o,e.start+g))}let h=r-e.start*this._itemSize;if(h<this._minBufferPx&&e.start!=0){let g=Math.ceil((this._maxBufferPx-h)/this._itemSize);e.start=Math.max(0,e.start-g),e.end=Math.min(o,Math.ceil(m+(t+this._minBufferPx)/this._itemSize))}else{let g=e.end*this._itemSize-(r+t);if(g<this._minBufferPx&&e.end!=o){let d=Math.ceil((this._maxBufferPx-g)/this._itemSize);d>0&&(e.end=Math.min(o,e.end+d),e.start=Math.max(0,Math.floor(m-this._minBufferPx/this._itemSize)))}}this._viewport.setRenderedRange(e),this._viewport.setRenderedContentOffset(Math.round(this._itemSize*e.start)),this._scrolledIndexChange.next(Math.floor(m))}};function ii(i){return i._scrollStrategy}var xn=(()=>{class i{get itemSize(){return this._itemSize}set itemSize(e){this._itemSize=be(e)}_itemSize=20;get minBufferPx(){return this._minBufferPx}set minBufferPx(e){this._minBufferPx=be(e)}_minBufferPx=100;get maxBufferPx(){return this._maxBufferPx}set maxBufferPx(e){this._maxBufferPx=be(e)}_maxBufferPx=200;_scrollStrategy=new dt(this.itemSize,this.minBufferPx,this.maxBufferPx);ngOnChanges(){this._scrollStrategy.updateItemAndBufferSize(this.itemSize,this.minBufferPx,this.maxBufferPx)}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,selectors:[["cdk-virtual-scroll-viewport","itemSize",""]],inputs:{itemSize:"itemSize",minBufferPx:"minBufferPx",maxBufferPx:"maxBufferPx"},features:[ue([{provide:Cn,useFactory:ii,deps:[bt(()=>i)]}]),ke]})}return i})(),oi=20,ri=(()=>{class i{_ngZone=f(fe);_platform=f(He);_renderer=f(Je).createRenderer(null,null);_cleanupGlobalListener;constructor(){}_scrolled=new N;_scrolledCount=0;scrollContainers=new Map;register(e){this.scrollContainers.has(e)||this.scrollContainers.set(e,e.elementScrolled().subscribe(()=>this._scrolled.next(e)))}deregister(e){let t=this.scrollContainers.get(e);t&&(t.unsubscribe(),this.scrollContainers.delete(e))}scrolled(e=oi){return this._platform.isBrowser?new Ke(t=>{this._cleanupGlobalListener||(this._cleanupGlobalListener=this._ngZone.runOutsideAngular(()=>this._renderer.listen("document","scroll",()=>this._scrolled.next())));let o=e>0?this._scrolled.pipe(Me(e)).subscribe(t):this._scrolled.subscribe(t);return this._scrolledCount++,()=>{o.unsubscribe(),this._scrolledCount--,this._scrolledCount||(this._cleanupGlobalListener?.(),this._cleanupGlobalListener=void 0)}}):W()}ngOnDestroy(){this._cleanupGlobalListener?.(),this._cleanupGlobalListener=void 0,this.scrollContainers.forEach((e,t)=>this.deregister(t)),this._scrolled.complete()}ancestorScrolled(e,t){let o=this.getAncestorScrollContainers(e);return this.scrolled(t).pipe(ht(r=>!r||o.indexOf(r)>-1))}getAncestorScrollContainers(e){let t=[];return this.scrollContainers.forEach((o,r)=>{this._scrollableContainsElement(r,e)&&t.push(r)}),t}_scrollableContainsElement(e,t){let o=pn(t),r=e.getElementRef().nativeElement;do if(o==r)return!0;while(o=o.parentElement);return!1}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})(),bn=(()=>{class i{elementRef=f(me);scrollDispatcher=f(ri);ngZone=f(fe);dir=f(fn,{optional:!0});_scrollElement=this.elementRef.nativeElement;_destroyed=new N;_renderer=f(kt);_cleanupScroll;_elementScrolled=new N;constructor(){}ngOnInit(){this._cleanupScroll=this.ngZone.runOutsideAngular(()=>this._renderer.listen(this._scrollElement,"scroll",e=>this._elementScrolled.next(e))),this.scrollDispatcher.register(this)}ngOnDestroy(){this._cleanupScroll?.(),this._elementScrolled.complete(),this.scrollDispatcher.deregister(this),this._destroyed.next(),this._destroyed.complete()}elementScrolled(){return this._elementScrolled}getElementRef(){return this.elementRef}scrollTo(e){let t=this.elementRef.nativeElement,o=this.dir&&this.dir.value=="rtl";e.left==null&&(e.left=o?e.end:e.start),e.right==null&&(e.right=o?e.start:e.end),e.bottom!=null&&(e.top=t.scrollHeight-t.clientHeight-e.bottom),o&&ae()!=A.NORMAL?(e.left!=null&&(e.right=t.scrollWidth-t.clientWidth-e.left),ae()==A.INVERTED?e.left=e.right:ae()==A.NEGATED&&(e.left=e.right?-e.right:e.right)):e.right!=null&&(e.left=t.scrollWidth-t.clientWidth-e.right),this._applyScrollToOptions(e)}_applyScrollToOptions(e){let t=this.elementRef.nativeElement;gn()?t.scrollTo(e):(e.top!=null&&(t.scrollTop=e.top),e.left!=null&&(t.scrollLeft=e.left))}measureScrollOffset(e){let t="left",o="right",r=this.elementRef.nativeElement;if(e=="top")return r.scrollTop;if(e=="bottom")return r.scrollHeight-r.clientHeight-r.scrollTop;let m=this.dir&&this.dir.value=="rtl";return e=="start"?e=m?o:t:e=="end"&&(e=m?t:o),m&&ae()==A.INVERTED?e==t?r.scrollWidth-r.clientWidth-r.scrollLeft:r.scrollLeft:m&&ae()==A.NEGATED?e==t?r.scrollLeft+r.scrollWidth-r.clientWidth:-r.scrollLeft:e==t?r.scrollLeft:r.scrollWidth-r.clientWidth-r.scrollLeft}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,selectors:[["","cdk-scrollable",""],["","cdkScrollable",""]]})}return i})(),ai=20,si=(()=>{class i{_platform=f(He);_listeners;_viewportSize;_change=new N;_document=f(De);constructor(){let e=f(fe),t=f(Je).createRenderer(null,null);e.runOutsideAngular(()=>{if(this._platform.isBrowser){let o=r=>this._change.next(r);this._listeners=[t.listen("window","resize",o),t.listen("window","orientationchange",o)]}this.change().subscribe(()=>this._viewportSize=null)})}ngOnDestroy(){this._listeners?.forEach(e=>e()),this._change.complete()}getViewportSize(){this._viewportSize||this._updateViewportSize();let e={width:this._viewportSize.width,height:this._viewportSize.height};return this._platform.isBrowser||(this._viewportSize=null),e}getViewportRect(){let e=this.getViewportScrollPosition(),{width:t,height:o}=this.getViewportSize();return{top:e.top,left:e.left,bottom:e.top+o,right:e.left+t,height:o,width:t}}getViewportScrollPosition(){if(!this._platform.isBrowser)return{top:0,left:0};let e=this._document,t=this._getWindow(),o=e.documentElement,r=o.getBoundingClientRect(),m=-r.top||e.body.scrollTop||t.scrollY||o.scrollTop||0,h=-r.left||e.body.scrollLeft||t.scrollX||o.scrollLeft||0;return{top:m,left:h}}change(e=ai){return e>0?this._change.pipe(Me(e)):this._change}_getWindow(){return this._document.defaultView||window}_updateViewportSize(){let e=this._getWindow();this._viewportSize=this._platform.isBrowser?{width:e.innerWidth,height:e.innerHeight}:{width:0,height:0}}static \u0275fac=function(t){return new(t||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})}return i})(),hn=new Q("VIRTUAL_SCROLLABLE"),li=(()=>{class i extends bn{constructor(){super()}measureViewportSize(e){let t=this.elementRef.nativeElement;return e==="horizontal"?t.clientWidth:t.clientHeight}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,features:[et]})}return i})();function ci(i,n){return i.start==n.start&&i.end==n.end}var di=typeof requestAnimationFrame<"u"?ut:gt,mt=(()=>{class i extends li{elementRef=f(me);_changeDetectorRef=f(Gt);_scrollStrategy=f(Cn,{optional:!0});scrollable=f(hn,{optional:!0});_platform=f(He);_detachedSubject=new N;_renderedRangeSubject=new N;get orientation(){return this._orientation}set orientation(e){this._orientation!==e&&(this._orientation=e,this._calculateSpacerSize())}_orientation="vertical";appendOnly=!1;scrolledIndexChange=new Ke(e=>this._scrollStrategy.scrolledIndexChange.subscribe(t=>Promise.resolve().then(()=>this.ngZone.run(()=>e.next(t)))));_contentWrapper;renderedRangeStream=this._renderedRangeSubject;_totalContentSize=0;_totalContentWidth=x("");_totalContentHeight=x("");_renderedContentTransform;_renderedRange={start:0,end:0};_dataLength=0;_viewportSize=0;_forOf;_renderedContentOffset=0;_renderedContentOffsetNeedsRewrite=!1;_changeDetectionNeeded=x(!1);_runAfterChangeDetection=[];_viewportChanges=pt.EMPTY;_injector=f(yt);_isDestroyed=!1;constructor(){super();let e=f(si);this._scrollStrategy,this._viewportChanges=e.change().subscribe(()=>{this.checkViewportSize()}),this.scrollable||(this.elementRef.nativeElement.classList.add("cdk-virtual-scrollable"),this.scrollable=this);let t=j(()=>{this._changeDetectionNeeded()&&this._doChangeDetection()},{injector:f(Tt).injector});f(St).onDestroy(()=>void t.destroy())}ngOnInit(){this._platform.isBrowser&&(this.scrollable===this&&super.ngOnInit(),this.ngZone.runOutsideAngular(()=>Promise.resolve().then(()=>{this._measureViewportSize(),this._scrollStrategy.attach(this),this.scrollable.elementScrolled().pipe(Xe(null),Me(0,di),Ee(this._destroyed)).subscribe(()=>this._scrollStrategy.onContentScrolled()),this._markChangeDetectionNeeded()})))}ngOnDestroy(){this.detach(),this._scrollStrategy.detach(),this._renderedRangeSubject.complete(),this._detachedSubject.complete(),this._viewportChanges.unsubscribe(),this._isDestroyed=!0,super.ngOnDestroy()}attach(e){this._forOf,this.ngZone.runOutsideAngular(()=>{this._forOf=e,this._forOf.dataStream.pipe(Ee(this._detachedSubject)).subscribe(t=>{let o=t.length;o!==this._dataLength&&(this._dataLength=o,this._scrollStrategy.onDataLengthChanged()),this._doChangeDetection()})})}detach(){this._forOf=null,this._detachedSubject.next()}getDataLength(){return this._dataLength}getViewportSize(){return this._viewportSize}getRenderedRange(){return this._renderedRange}measureBoundingClientRectWithScrollOffset(e){return this.getElementRef().nativeElement.getBoundingClientRect()[e]}setTotalContentSize(e){this._totalContentSize!==e&&(this._totalContentSize=e,this._calculateSpacerSize(),this._markChangeDetectionNeeded())}setRenderedRange(e){ci(this._renderedRange,e)||(this.appendOnly&&(e={start:0,end:Math.max(this._renderedRange.end,e.end)}),this._renderedRangeSubject.next(this._renderedRange=e),this._markChangeDetectionNeeded(()=>this._scrollStrategy.onContentRendered()))}getOffsetToRenderedContentStart(){return this._renderedContentOffsetNeedsRewrite?null:this._renderedContentOffset}setRenderedContentOffset(e,t="to-start"){e=this.appendOnly&&t==="to-start"?0:e;let o=this.dir&&this.dir.value=="rtl",r=this.orientation=="horizontal",m=r?"X":"Y",g=`translate${m}(${Number((r&&o?-1:1)*e)}px)`;this._renderedContentOffset=e,t==="to-end"&&(g+=` translate${m}(-100%)`,this._renderedContentOffsetNeedsRewrite=!0),this._renderedContentTransform!=g&&(this._renderedContentTransform=g,this._markChangeDetectionNeeded(()=>{this._renderedContentOffsetNeedsRewrite?(this._renderedContentOffset-=this.measureRenderedContentSize(),this._renderedContentOffsetNeedsRewrite=!1,this.setRenderedContentOffset(this._renderedContentOffset)):this._scrollStrategy.onRenderedOffsetChanged()}))}scrollToOffset(e,t="auto"){let o={behavior:t};this.orientation==="horizontal"?o.start=e:o.top=e,this.scrollable.scrollTo(o)}scrollToIndex(e,t="auto"){this._scrollStrategy.scrollToIndex(e,t)}measureScrollOffset(e){let t;return this.scrollable==this?t=o=>super.measureScrollOffset(o):t=o=>this.scrollable.measureScrollOffset(o),Math.max(0,t(e??(this.orientation==="horizontal"?"start":"top"))-this.measureViewportOffset())}measureViewportOffset(e){let t,o="left",r="right",m=this.dir?.value=="rtl";e=="start"?t=m?r:o:e=="end"?t=m?o:r:e?t=e:t=this.orientation==="horizontal"?"left":"top";let h=this.scrollable.measureBoundingClientRectWithScrollOffset(t);return this.elementRef.nativeElement.getBoundingClientRect()[t]-h}measureRenderedContentSize(){let e=this._contentWrapper.nativeElement;return this.orientation==="horizontal"?e.offsetWidth:e.offsetHeight}measureRangeSize(e){return this._forOf?this._forOf.measureRangeSize(e,this.orientation):0}checkViewportSize(){this._measureViewportSize(),this._scrollStrategy.onDataLengthChanged()}_measureViewportSize(){this._viewportSize=this.scrollable.measureViewportSize(this.orientation)}_markChangeDetectionNeeded(e){e&&this._runAfterChangeDetection.push(e),!jt(this._changeDetectionNeeded)&&this.ngZone.runOutsideAngular(()=>{Promise.resolve().then(()=>{this.ngZone.run(()=>{this._changeDetectionNeeded.set(!0)})})})}_doChangeDetection(){this._isDestroyed||this.ngZone.run(()=>{this._changeDetectorRef.markForCheck(),this._contentWrapper.nativeElement.style.transform=this._renderedContentTransform,It(()=>{this._changeDetectionNeeded.set(!1);let e=this._runAfterChangeDetection;this._runAfterChangeDetection=[];for(let t of e)t()},{injector:this._injector})})}_calculateSpacerSize(){this._totalContentHeight.set(this.orientation==="horizontal"?"":`${this._totalContentSize}px`),this._totalContentWidth.set(this.orientation==="horizontal"?`${this._totalContentSize}px`:"")}static \u0275fac=function(t){return new(t||i)};static \u0275cmp=D({type:i,selectors:[["cdk-virtual-scroll-viewport"]],viewQuery:function(t,o){if(t&1&&q(ti,7),t&2){let r;K(r=X())&&(o._contentWrapper=r.first)}},hostAttrs:[1,"cdk-virtual-scroll-viewport"],hostVars:4,hostBindings:function(t,o){t&2&&z("cdk-virtual-scroll-orientation-horizontal",o.orientation==="horizontal")("cdk-virtual-scroll-orientation-vertical",o.orientation!=="horizontal")},inputs:{orientation:"orientation",appendOnly:[2,"appendOnly","appendOnly",$t]},outputs:{scrolledIndexChange:"scrolledIndexChange"},features:[ue([{provide:bn,useFactory:(e,t)=>e||t,deps:[[new Ot,new Mt(hn)],i]}]),et],ngContentSelectors:ni,decls:4,vars:4,consts:[["contentWrapper",""],[1,"cdk-virtual-scroll-content-wrapper"],[1,"cdk-virtual-scroll-spacer"]],template:function(t,o){t&1&&(zt(),Nt(0,"div",1,0),Lt(2),Vt(),Ft(3,"div",2)),t&2&&(s(3),J("width",o._totalContentWidth())("height",o._totalContentHeight()))},styles:[`cdk-virtual-scroll-viewport{display:block;position:relative;transform:translateZ(0)}.cdk-virtual-scrollable{overflow:auto;will-change:scroll-position;contain:strict}.cdk-virtual-scroll-content-wrapper{position:absolute;top:0;left:0;contain:content}[dir=rtl] .cdk-virtual-scroll-content-wrapper{right:0;left:auto}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper{min-height:100%}.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-horizontal .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-left:0;padding-right:0;margin-left:0;margin-right:0;border-left-width:0;border-right-width:0;outline:none}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper{min-width:100%}.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>dl:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ol:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>table:not([cdkVirtualFor]),.cdk-virtual-scroll-orientation-vertical .cdk-virtual-scroll-content-wrapper>ul:not([cdkVirtualFor]){padding-top:0;padding-bottom:0;margin-top:0;margin-bottom:0;border-top-width:0;border-bottom-width:0;outline:none}.cdk-virtual-scroll-spacer{height:1px;transform-origin:0 0;flex:0 0 auto}[dir=rtl] .cdk-virtual-scroll-spacer{transform-origin:100% 0}
2
+ `],encapsulation:2,changeDetection:0})}return i})();function _n(i,n,e){let t=e;if(!t.getBoundingClientRect)return 0;let o=t.getBoundingClientRect();return i==="horizontal"?n==="start"?o.left:o.right:n==="start"?o.top:o.bottom}var wn=(()=>{class i{_viewContainerRef=f(Pt);_template=f(Dt);_differs=f(Ht);_viewRepeater=f(ct);_viewport=f(mt,{skipSelf:!0});viewChange=new N;_dataSourceChanges=new N;get cdkVirtualForOf(){return this._cdkVirtualForOf}set cdkVirtualForOf(e){this._cdkVirtualForOf=e,un(e)?this._dataSourceChanges.next(e):this._dataSourceChanges.next(new Ue(Se(e)?e:Array.from(e||[])))}_cdkVirtualForOf;get cdkVirtualForTrackBy(){return this._cdkVirtualForTrackBy}set cdkVirtualForTrackBy(e){this._needsUpdate=!0,this._cdkVirtualForTrackBy=e?(t,o)=>e(t+(this._renderedRange?this._renderedRange.start:0),o):void 0}_cdkVirtualForTrackBy;set cdkVirtualForTemplate(e){e&&(this._needsUpdate=!0,this._template=e)}get cdkVirtualForTemplateCacheSize(){return this._viewRepeater.viewCacheSize}set cdkVirtualForTemplateCacheSize(e){this._viewRepeater.viewCacheSize=be(e)}dataStream=this._dataSourceChanges.pipe(Xe(null),Ct(),Oe(([e,t])=>this._changeDataSource(e,t)),xt(1));_differ=null;_data;_renderedItems;_renderedRange;_needsUpdate=!1;_destroyed=new N;constructor(){let e=f(fe);this.dataStream.subscribe(t=>{this._data=t,this._onRenderedDataChange()}),this._viewport.renderedRangeStream.pipe(Ee(this._destroyed)).subscribe(t=>{this._renderedRange=t,this.viewChange.observers.length&&e.run(()=>this.viewChange.next(this._renderedRange)),this._onRenderedDataChange()}),this._viewport.attach(this)}measureRangeSize(e,t){if(e.start>=e.end)return 0;e.start<this._renderedRange.start||e.end>this._renderedRange.end;let o=e.start-this._renderedRange.start,r=e.end-e.start,m,h;for(let g=0;g<r;g++){let d=this._viewContainerRef.get(g+o);if(d&&d.rootNodes.length){m=h=d.rootNodes[0];break}}for(let g=r-1;g>-1;g--){let d=this._viewContainerRef.get(g+o);if(d&&d.rootNodes.length){h=d.rootNodes[d.rootNodes.length-1];break}}return m&&h?_n(t,"end",h)-_n(t,"start",m):0}ngDoCheck(){if(this._differ&&this._needsUpdate){let e=this._differ.diff(this._renderedItems);e?this._applyChanges(e):this._updateContext(),this._needsUpdate=!1}}ngOnDestroy(){this._viewport.detach(),this._dataSourceChanges.next(void 0),this._dataSourceChanges.complete(),this.viewChange.complete(),this._destroyed.next(),this._destroyed.complete(),this._viewRepeater.detach()}_onRenderedDataChange(){this._renderedRange&&(this._renderedItems=this._data.slice(this._renderedRange.start,this._renderedRange.end),this._differ||(this._differ=this._differs.find(this._renderedItems).create((e,t)=>this.cdkVirtualForTrackBy?this.cdkVirtualForTrackBy(e,t):t)),this._needsUpdate=!0)}_changeDataSource(e,t){return e&&e.disconnect(this),this._needsUpdate=!0,t?t.connect(this):W()}_updateContext(){let e=this._data.length,t=this._viewContainerRef.length;for(;t--;){let o=this._viewContainerRef.get(t);o.context.index=this._renderedRange.start+t,o.context.count=e,this._updateComputedContextProperties(o.context),o.detectChanges()}}_applyChanges(e){this._viewRepeater.applyChanges(e,this._viewContainerRef,(r,m,h)=>this._getEmbeddedViewArgs(r,h),r=>r.item),e.forEachIdentityChange(r=>{let m=this._viewContainerRef.get(r.currentIndex);m.context.$implicit=r.item});let t=this._data.length,o=this._viewContainerRef.length;for(;o--;){let r=this._viewContainerRef.get(o);r.context.index=this._renderedRange.start+o,r.context.count=t,this._updateComputedContextProperties(r.context)}}_updateComputedContextProperties(e){e.first=e.index===0,e.last=e.index===e.count-1,e.even=e.index%2===0,e.odd=!e.even}_getEmbeddedViewArgs(e,t){return{templateRef:this._template,context:{$implicit:e.item,cdkVirtualForOf:this._cdkVirtualForOf,index:-1,count:-1,first:!1,last:!1,odd:!1,even:!1},index:t}}static ngTemplateContextGuard(e,t){return!0}static \u0275fac=function(t){return new(t||i)};static \u0275dir=oe({type:i,selectors:[["","cdkVirtualFor","","cdkVirtualForOf",""]],inputs:{cdkVirtualForOf:"cdkVirtualForOf",cdkVirtualForTrackBy:"cdkVirtualForTrackBy",cdkVirtualForTemplate:"cdkVirtualForTemplate",cdkVirtualForTemplateCacheSize:"cdkVirtualForTemplateCacheSize"},features:[ue([{provide:ct,useClass:Ye}])]})}return i})();var vn=(()=>{class i{static \u0275fac=function(t){return new(t||i)};static \u0275mod=pe({type:i});static \u0275inj=de({})}return i})(),yn=(()=>{class i{static \u0275fac=function(t){return new(t||i)};static \u0275mod=pe({type:i});static \u0275inj=de({imports:[lt,vn,lt,vn]})}return i})();function pi(i,n){i&1&&b(0,"span",19)}function fi(i,n){if(i&1&&(l(0,"span",23),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function gi(i,n){if(i&1&&(l(0,"span",24),c(1),a()),i&2){let e=n.$implicit;s(),_(e)}}function ui(i,n){if(i&1&&(l(0,"span",20),v(1,fi,2,1,"span",21)(2,gi,2,1,"span",22),a()),i&2){let e=C().$implicit;s(),u("ngForOf",e.tags),s(),u("ngForOf",e.branches)}}function hi(i,n){if(i&1){let e=F();l(0,"button",7),S("click",function(){let o=M(e).$implicit,r=C();return O(r.select(o))}),l(1,"span",8),b(2,"span",9),v(3,pi,1,0,"span",10),a(),l(4,"span",11)(5,"span",12),c(6),a(),l(7,"span",13)(8,"span",14),c(9),a(),l(10,"span",15),c(11,"\u2022"),a(),l(12,"span",16),c(13),a(),l(14,"span",15),c(15,"\u2022"),a(),l(16,"span",17),c(17),he(18,"date"),a()()(),v(19,ui,3,2,"span",18),a()}if(i&2){let e=n.$implicit,t=n.index,o=C();z("selected",e.hash===o.selectedHash()),ge("aria-current",e.hash===o.selectedHash()?"true":null),s(2),J("background",o.laneColor(e)),z("merge",e.isMerge),s(),u("ngIf",t<o.commits().length-1),s(2),u("title",e.subject),s(),_(e.subject),s(3),_(e.shortHash),s(4),_(e.author),s(4),_(_e(18,14,e.date,"MMM d, y, h:mm a")),s(2),u("ngIf",e.branches.length||e.tags.length)}}function _i(i,n){i&1&&(l(0,"div",25)(1,"p"),c(2,"No commits match your filters."),a()())}var Ze=class i{state=f(G);commits=this.state.commits;selectedHash=this.state.selectedHash;trackByHash(n,e){return e.hash}select(n){this.state.selectHash(n.hash)}laneColors=["#4f46e5","#06b6d4","#f59e0b","#ef4444","#10b981","#8b5cf6"];laneColor(n){let e=0,t=n.branches[0]??n.parents[0]??n.hash;for(let o=0;o<t.length;o++)e=e*31+t.charCodeAt(o)>>>0;return this.laneColors[e%this.laneColors.length]}onKey(n){if(!this.isTyping(n.target)){if(n.key==="j")n.preventDefault(),this.state.selectByOffset(1);else if(n.key==="k")n.preventDefault(),this.state.selectByOffset(-1);else if(n.key==="g"){n.preventDefault();let e=this.state.commits();e.length&&this.state.selectHash(e[0].hash)}else if(n.key==="G"){n.preventDefault();let e=this.state.commits();e.length&&this.state.selectHash(e[e.length-1].hash)}}}isTyping(n){return n instanceof HTMLElement?["INPUT","TEXTAREA","SELECT"].includes(n.tagName)||n.isContentEditable:!1}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-commit-list"]],hostBindings:function(e,t){e&1&&S("keydown",function(r){return t.onKey(r)},Pe)},decls:13,vars:6,consts:[[1,"header"],[1,"count"],[1,"hint"],[1,"kbd"],["minBufferPx","640","maxBufferPx","1280",1,"viewport",3,"itemSize"],["class","row",3,"selected","click",4,"cdkVirtualFor","cdkVirtualForOf","cdkVirtualForTrackBy"],["class","empty",4,"ngIf"],[1,"row",3,"click"],[1,"lane"],[1,"dot"],["class","line",4,"ngIf"],[1,"content"],[1,"subject",3,"title"],[1,"meta"],[1,"hash"],[1,"dot-sep"],[1,"author"],[1,"date"],["class","badges",4,"ngIf"],[1,"line"],[1,"badges"],["class","badge tag",4,"ngFor","ngForOf"],["class","badge branch",4,"ngFor","ngForOf"],[1,"badge","tag"],[1,"badge","branch"],[1,"empty"]],template:function(e,t){e&1&&(l(0,"div",0)(1,"span",1),c(2),a(),l(3,"span",2)(4,"kbd",3),c(5,"j"),a(),c(6,"/"),l(7,"kbd",3),c(8,"k"),a(),c(9," navigate "),a()(),l(10,"cdk-virtual-scroll-viewport",4),v(11,hi,20,17,"button",5)(12,_i,3,0,"div",6),a()),e&2&&(s(2),Ne("",t.commits().length," of ",t.state.total()),s(8),u("itemSize",64),s(),u("cdkVirtualForOf",t.commits())("cdkVirtualForTrackBy",t.trackByHash),s(),u("ngIf",!t.commits().length&&!t.state.loading()))},dependencies:[T,U,I,yn,xn,wn,mt,Fe],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;min-height:0;background:var(--bg-surface);border-right:1px solid var(--border-soft)}.header[_ngcontent-%COMP%]{display:flex;align-items:center;justify-content:space-between;padding:.5rem .85rem;border-bottom:1px solid var(--border-soft);font-size:12px;color:var(--fg-muted);background:var(--bg-surface)}.viewport[_ngcontent-%COMP%]{flex:1;min-height:0}.row[_ngcontent-%COMP%]{display:grid;grid-template-columns:24px 1fr auto;gap:.5rem;align-items:center;width:100%;height:64px;padding:.45rem .85rem;background:transparent;border:0;border-bottom:1px solid var(--border-soft);color:inherit;text-align:left;cursor:pointer;transition:background .1s}.row[_ngcontent-%COMP%]:hover{background:var(--bg-hover)}.row.selected[_ngcontent-%COMP%]{background:var(--bg-selected)}.row.selected[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{color:var(--fg-primary)}.lane[_ngcontent-%COMP%]{position:relative;width:24px;height:100%;display:flex;align-items:center;justify-content:center}.dot[_ngcontent-%COMP%]{width:10px;height:10px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 2px var(--bg-surface);z-index:1}.dot.merge[_ngcontent-%COMP%]{background:transparent;border:2px solid var(--accent)}.line[_ngcontent-%COMP%]{position:absolute;top:50%;left:50%;width:2px;height:50%;background:var(--border-strong);transform:translate(-50%)}.content[_ngcontent-%COMP%]{display:flex;flex-direction:column;min-width:0;gap:2px}.subject[_ngcontent-%COMP%]{font-weight:500;color:var(--fg-primary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.meta[_ngcontent-%COMP%]{display:flex;gap:6px;font-size:11px;color:var(--fg-muted);align-items:center}.hash[_ngcontent-%COMP%]{font-family:var(--font-mono)}.dot-sep[_ngcontent-%COMP%]{opacity:.5}.badges[_ngcontent-%COMP%]{display:flex;gap:4px;flex-wrap:wrap}.badge[_ngcontent-%COMP%]{font-size:10px;font-weight:600;padding:2px 6px;border-radius:999px;letter-spacing:.02em}.badge.tag[_ngcontent-%COMP%]{background:#d9770626;color:var(--warning)}.badge.branch[_ngcontent-%COMP%]{background:var(--accent-soft);color:var(--accent)}.empty[_ngcontent-%COMP%]{padding:2rem 1rem;text-align:center;color:var(--fg-muted)}"],changeDetection:0})};var Qe=class i{http=f(ze);base="/api";list(n={}){let e=new Ut;for(let[t,o]of Object.entries(n))o&&(e=e.set(t,String(o)));return this.http.get(`${this.base}/groups`,{params:e})}static \u0275fac=function(e){return new(e||i)};static \u0275prov=V({token:i,factory:i.\u0275fac,providedIn:"root"})};function vi(i,n){if(i&1&&(l(0,"span",7),c(1),a()),i&2){let e=n.ngIf;s(),B("",e," groups")}}function Ci(i,n){i&1&&(l(0,"div",8),c(1,"Loading groups\u2026"),a())}function xi(i,n){if(i&1&&(l(0,"div",9),c(1),a()),i&2){let e=n.ngIf;s(),_(e)}}function bi(i,n){i&1&&(l(0,"div",8),c(1," No groups detected. Try the flat view. "),a())}function wi(i,n){if(i&1&&(l(0,"span",18),c(1),a()),i&2){let e=C().$implicit;s(),B("#",e.prNumber)}}function yi(i,n){if(i&1){let e=F();l(0,"li",21),S("click",function(){let o=M(e).$implicit,r=C(3);return O(r.state.selectHash(o))}),l(1,"code",22),c(2),a(),l(3,"span",23),c(4),a()()}if(i&2){let e=n.$implicit,t=C(3);z("selected",e===t.state.selectedHash()),s(2),_(t.shortHash(e)),s(2),_(t.subjectFor(e))}}function Si(i,n){if(i&1&&(l(0,"ul",19),v(1,yi,5,4,"li",20),a()),i&2){let e=C().$implicit;s(),u("ngForOf",e.commits)}}function Mi(i,n){if(i&1){let e=F();l(0,"li",10)(1,"button",11),S("click",function(){let o=M(e).$implicit,r=C();return O(r.toggle(o.id))}),l(2,"span",12),c(3,"\u25B8"),a(),l(4,"span",13),c(5),a(),v(6,wi,2,1,"span",14),l(7,"span",15),c(8),a(),l(9,"span",16),c(10),a()(),v(11,Si,2,1,"ul",17),a()}if(i&2){let e=n.$implicit,t=C();z("expanded",t.isExpanded(e.id)),s(2),z("open",t.isExpanded(e.id)),s(2),At("src-"+e.source),s(),_(t.sourceLabel(e.source)),s(),u("ngIf",e.prNumber),s(2),_(e.title),s(2),_(e.commits.length),s(),u("ngIf",t.isExpanded(e.id))}}var qe=class i{state=f(G);groupsApi=f(Qe);groups=x(null);loading=x(!1);error=x(null);expanded=x(new Set);subjectMap=ee(()=>{let n=new Map;for(let e of this.state.commits())n.set(e.hash,e.subject);return n});constructor(){j(()=>{let n=this.state.filters();this.load(n.since,n.until,n.author)})}isExpanded(n){return this.expanded().has(n)}toggle(n){let e=new Set(this.expanded());e.has(n)?e.delete(n):e.add(n),this.expanded.set(e)}shortHash(n){return n.slice(0,7)}subjectFor(n){return this.subjectMap().get(n)??n.slice(0,7)}sourceLabel(n){switch(n){case"merge":return"PR";case"squash":return"PR (sq)";case"conventional":return"Feat";case"standalone":return"commit"}}load(n,e,t){this.loading.set(!0),this.error.set(null),this.groupsApi.list({since:n,until:e,author:t}).subscribe({next:o=>{this.groups.set(o),this.loading.set(!1);let r=o.find(m=>m.prNumber);r&&this.expanded.set(new Set([r.id]))},error:o=>{this.error.set(this.errMsg(o)),this.loading.set(!1)}})}errMsg(n){if(n&&typeof n=="object"&&"error"in n){let e=n.error;if(e?.error)return e.error}return n instanceof Error?n.message:"Failed to load groups"}static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-grouped-list"]],decls:9,vars:5,consts:[[1,"head"],[1,"title"],["class","meta",4,"ngIf"],["class","empty",4,"ngIf"],["class","empty error",4,"ngIf"],[1,"groups"],["class","group",3,"expanded",4,"ngFor","ngForOf"],[1,"meta"],[1,"empty"],[1,"empty","error"],[1,"group"],[1,"group-head",3,"click"],[1,"caret"],[1,"badge"],["class","pr",4,"ngIf"],[1,"g-title"],[1,"count"],["class","commits",4,"ngIf"],[1,"pr"],[1,"commits"],["class","commit",3,"selected","click",4,"ngFor","ngForOf"],[1,"commit",3,"click"],[1,"hash"],[1,"subject"]],template:function(e,t){if(e&1&&(l(0,"div",0)(1,"span",1),c(2,"PR / feature groups"),a(),v(3,vi,2,1,"span",2),a(),v(4,Ci,2,0,"div",3)(5,xi,2,1,"div",4)(6,bi,2,0,"div",3),l(7,"ul",5),v(8,Mi,12,11,"li",6),a()),e&2){let o,r;s(3),u("ngIf",(o=t.groups())==null?null:o.length),s(),u("ngIf",t.loading()),s(),u("ngIf",t.error()),s(),u("ngIf",!t.loading()&&!t.error()&&(((r=t.groups())==null?null:r.length)??0)===0),s(2),u("ngForOf",t.groups())}},dependencies:[T,U,I],styles:["[_nghost-%COMP%]{display:flex;flex-direction:column;height:100%;overflow:hidden}.head[_ngcontent-%COMP%]{display:flex;justify-content:space-between;padding:.6rem .85rem;border-bottom:1px solid var(--border-soft);background:var(--bg-surface)}.title[_ngcontent-%COMP%]{font-weight:600;font-size:13px}.meta[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted)}.empty[_ngcontent-%COMP%]{padding:1rem .85rem;color:var(--fg-muted);font-size:12px}.empty.error[_ngcontent-%COMP%]{color:var(--danger)}.groups[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0;overflow-y:auto;flex:1}.group[_ngcontent-%COMP%]{border-bottom:1px solid var(--border-soft)}.group-head[_ngcontent-%COMP%]{width:100%;display:flex;align-items:center;gap:.5rem;padding:.55rem .85rem;background:transparent;border:0;color:var(--fg-primary);cursor:pointer;text-align:left}.group-head[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.caret[_ngcontent-%COMP%]{display:inline-block;width:10px;transition:transform .15s ease;color:var(--fg-muted)}.caret.open[_ngcontent-%COMP%]{transform:rotate(90deg)}.badge[_ngcontent-%COMP%]{font-size:10px;letter-spacing:.04em;padding:1px 6px;border-radius:3px;background:var(--bg-elevated);color:var(--fg-secondary);text-transform:uppercase}.badge.src-merge[_ngcontent-%COMP%]{background:#6366f12e;color:var(--accent)}.badge.src-squash[_ngcontent-%COMP%]{background:#10b9812e;color:#10b981}.badge.src-conventional[_ngcontent-%COMP%]{background:#f59e0b2e;color:#d97706}.pr[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted)}.g-title[_ngcontent-%COMP%]{flex:1;font-size:13px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.count[_ngcontent-%COMP%]{font-size:11px;color:var(--fg-muted);background:var(--bg-elevated);padding:1px 6px;border-radius:999px}.commits[_ngcontent-%COMP%]{list-style:none;margin:0;padding:0 0 .4rem;background:var(--bg-app)}.commit[_ngcontent-%COMP%]{display:flex;gap:.6rem;align-items:center;padding:.3rem .85rem .3rem 2rem;cursor:pointer;font-size:12px}.commit[_ngcontent-%COMP%]:hover{background:var(--bg-elevated)}.commit.selected[_ngcontent-%COMP%]{background:color-mix(in oklab,var(--accent) 20%,transparent)}.commit[_ngcontent-%COMP%] .hash[_ngcontent-%COMP%]{font-family:var(--font-mono, monospace);font-size:11px;color:var(--fg-muted)}.commit[_ngcontent-%COMP%] .subject[_ngcontent-%COMP%]{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}"],changeDetection:0})};function Oi(i,n){i&1&&(Re(0),b(1,"app-grouped-list"),Ie())}function Ei(i,n){i&1&&b(0,"app-commit-list")}var Sn=class i{state=f(G);static \u0275fac=function(e){return new(e||i)};static \u0275cmp=D({type:i,selectors:[["app-home-shell"]],decls:9,vars:2,consts:[["flat",""],[1,"layout"],[1,"pane","graph"],[1,"pane","list"],[4,"ngIf","ngIfElse"],[1,"pane","detail"]],template:function(e,t){if(e&1&&(l(0,"main",1)(1,"aside",2),b(2,"app-commit-graph"),a(),l(3,"section",3),v(4,Oi,2,0,"ng-container",4)(5,Ei,1,0,"ng-template",null,0,Ve),a(),l(7,"section",5),b(8,"app-commit-detail"),a()()),e&2){let o=Te(6);s(4),u("ngIf",t.state.viewMode()==="grouped")("ngIfElse",o)}},dependencies:[T,I,Ge,Ze,Be,qe],styles:["[_nghost-%COMP%]{display:block;flex:1;min-height:0}.layout[_ngcontent-%COMP%]{height:100%;display:grid;grid-template-columns:220px 380px 1fr;min-height:0}.pane[_ngcontent-%COMP%]{min-width:0;min-height:0;overflow:hidden}.pane.graph[_ngcontent-%COMP%]{border-right:1px solid var(--border-soft)}@media (max-width: 1100px){.layout[_ngcontent-%COMP%]{grid-template-columns:320px 1fr}.pane.graph[_ngcontent-%COMP%]{display:none}}@media (max-width: 720px){.layout[_ngcontent-%COMP%]{grid-template-columns:1fr}.pane.list[_ngcontent-%COMP%]{display:none}}"],changeDetection:0})};export{Sn as HomeShellComponent};
@@ -9,8 +9,8 @@
9
9
  <meta name="theme-color" content="#0b1020" media="(prefers-color-scheme: dark)">
10
10
  <meta name="theme-color" content="#f7f8fa" media="(prefers-color-scheme: light)">
11
11
  <link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%234f46e5' d='M12 .5a11.5 11.5 0 1 0 11.5 11.5A11.5 11.5 0 0 0 12 .5Zm5.7 14.83a1 1 0 0 1-1.41 1.41L13 13.41V19a1 1 0 0 1-2 0v-5.59l-3.29 3.33A1 1 0 1 1 6.3 15.34l5-5.05a1 1 0 0 1 1.42 0Z'/%3E%3C/svg%3E">
12
- <style>*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}:root{color-scheme:light;--bg-app:#f7f8fa;--bg-surface:#ffffff;--bg-surface-2:#f3f4f6;--bg-elevated:#ffffff;--bg-hover:#eef2ff;--bg-selected:#e0e7ff;--bg-overlay:rgba(15, 23, 42, .45);--fg-primary:#0f172a;--fg-secondary:#475569;--fg-muted:#64748b;--fg-subtle:#94a3b8;--fg-inverted:#ffffff;--border-soft:#e2e8f0;--border-strong:#cbd5e1;--border-focus:#6366f1;--accent:#4f46e5;--accent-hover:#4338ca;--accent-soft:#eef2ff;--accent-fg:#ffffff;--success:#16a34a;--warning:#d97706;--danger:#dc2626;--diff-add-bg:#dcfce7;--diff-add-fg:#14532d;--diff-add-gutter:#86efac;--diff-del-bg:#fee2e2;--diff-del-fg:#7f1d1d;--diff-del-gutter:#fca5a5;--diff-hunk-bg:#f1f5f9;--diff-hunk-fg:#475569;--graph-guide:rgba(148, 163, 184, .28);--graph-row-alt:rgba(15, 23, 42, .025);--graph-row-hover:rgba(79, 70, 229, .08);--graph-row-selected:rgba(79, 70, 229, .14);--graph-node-ring:#ffffff;--graph-shadow:rgba(15, 23, 42, .12);--shadow-sm:0 1px 2px rgba(15, 23, 42, .06);--shadow-md:0 4px 12px rgba(15, 23, 42, .08);--shadow-lg:0 12px 32px rgba(15, 23, 42, .12);--radius-sm:6px;--radius-md:10px;--radius-lg:14px;--font-sans:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Liberation Mono", "Courier New", monospace}*,*:before,*:after{box-sizing:border-box}html,body{height:100%}body{margin:0;font-family:var(--font-sans);font-size:14px;line-height:1.5;color:var(--fg-primary);background:var(--bg-app);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}</style><link rel="stylesheet" href="styles-BOEVKAI2.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles-BOEVKAI2.css"></noscript></head>
12
+ <style>*,:before,:after{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgb(59 130 246 / .5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }*,:before,:after{box-sizing:border-box;border-width:0;border-style:solid;border-color:#e5e7eb}:before,:after{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji",Segoe UI Symbol,"Noto Color Emoji";font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}:root{color-scheme:light;--bg-app:#f7f8fa;--bg-surface:#ffffff;--bg-surface-2:#f3f4f6;--bg-elevated:#ffffff;--bg-hover:#eef2ff;--bg-selected:#e0e7ff;--bg-overlay:rgba(15, 23, 42, .45);--fg-primary:#0f172a;--fg-secondary:#475569;--fg-muted:#64748b;--fg-subtle:#94a3b8;--fg-inverted:#ffffff;--border-soft:#e2e8f0;--border-strong:#cbd5e1;--border-focus:#6366f1;--accent:#4f46e5;--accent-hover:#4338ca;--accent-soft:#eef2ff;--accent-fg:#ffffff;--success:#16a34a;--warning:#d97706;--danger:#dc2626;--diff-add-bg:#dcfce7;--diff-add-fg:#14532d;--diff-add-gutter:#86efac;--diff-del-bg:#fee2e2;--diff-del-fg:#7f1d1d;--diff-del-gutter:#fca5a5;--diff-hunk-bg:#f1f5f9;--diff-hunk-fg:#475569;--graph-guide:rgba(148, 163, 184, .28);--graph-row-alt:rgba(15, 23, 42, .025);--graph-row-hover:rgba(79, 70, 229, .08);--graph-row-selected:rgba(79, 70, 229, .14);--graph-node-ring:#ffffff;--graph-shadow:rgba(15, 23, 42, .12);--shadow-sm:0 1px 2px rgba(15, 23, 42, .06);--shadow-md:0 4px 12px rgba(15, 23, 42, .08);--shadow-lg:0 12px 32px rgba(15, 23, 42, .12);--radius-sm:6px;--radius-md:10px;--radius-lg:14px;--font-sans:ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, "Cascadia Mono", "Liberation Mono", "Courier New", monospace}*,*:before,*:after{box-sizing:border-box}html,body{height:100%}body{margin:0;font-family:var(--font-sans);font-size:14px;line-height:1.5;color:var(--fg-primary);background:var(--bg-app);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility}</style><link rel="stylesheet" href="styles-AH3HC64Q.css" media="print" onload="this.media='all'"><noscript><link rel="stylesheet" href="styles-AH3HC64Q.css"></noscript></head>
13
13
  <body>
14
14
  <app-root></app-root>
15
- <link rel="modulepreload" href="chunk-36NFLS3P.js"><link rel="modulepreload" href="chunk-YSTG766K.js"><link rel="modulepreload" href="chunk-NUMLL3OZ.js"><link rel="modulepreload" href="chunk-N7UHDKJ7.js"><link rel="modulepreload" href="chunk-3FFYILBL.js"><link rel="modulepreload" href="chunk-TQE5NWMZ.js"><script src="polyfills-5CFQRCPP.js" type="module"></script><script src="main-AW2YOC32.js" type="module"></script></body>
15
+ <link rel="modulepreload" href="chunk-36NFLS3P.js"><link rel="modulepreload" href="chunk-YSTG766K.js"><link rel="modulepreload" href="chunk-NUMLL3OZ.js"><link rel="modulepreload" href="chunk-N7UHDKJ7.js"><link rel="modulepreload" href="chunk-3FFYILBL.js"><link rel="modulepreload" href="chunk-TQE5NWMZ.js"><script src="polyfills-5CFQRCPP.js" type="module"></script><script src="main-6GA6B4NK.js" type="module"></script></body>
16
16
  </html>