Mercurial
comparison hg-web/README.md @ 226:3fa4bf481f42
[merge] Merge hg-web into default
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Sun, 02 Aug 2026 14:42:01 -0700 |
| parents | 3007ef5fc0ed |
| children | 8bb0ac8f4587 |
comparison
equal
deleted
inserted
replaced
| 220:eb8b4230fdb9 | 226:3fa4bf481f42 |
|---|---|
| 1 # hg-web | 1 # hg-web |
| 2 | 2 |
| 3 A web-based Mercurial repository browser. Provides a GitHub-style interface for browsing files, viewing code with syntax highlighting, and reading markdown documentation. | 3 A custom Mercurial forge and repository browser. The application keeps the |
| 4 | 4 networking and HTTP stack in C with Seobeo, while the hand-drawn web interface |
| 5 ## Features | 5 is implemented in React and TypeScript. |
| 6 | 6 |
| 7 - Browse repository files and directories | 7 ## Wiki tree |
| 8 - View code files with syntax highlighting (highlight.js) | 8 |
| 9 - Render markdown files with WASM-based converter | 9 ```text |
| 10 - Dark/light theme support with system preference detection | 10 hg-web |
| 11 - Prefetch on hover for faster navigation | 11 ├── Runtime |
| 12 | 12 │ ├── hg_web_server :6970 |
| 13 ## Structure | 13 │ │ ├── React application and static assets |
| 14 | 14 │ │ ├── repository browsing API |
| 15 ``` | 15 │ │ ├── commit graph API |
| 16 hg-web/ | 16 │ │ └── Mercurial wire-protocol proxy |
| 17 ├── BUILD # Bazel build configuration | 17 │ └── hg serve :4444 |
| 18 ├── deploy.sh # Deployment script | 18 │ ├── repository files and graph data |
| 19 ├── main.c # C server handling API routes | 19 │ └── Mercurial pull/push protocol |
| 20 └── src/ # Frontend source files | 20 ├── Backend |
| 21 ``` | 21 │ ├── main.c |
| 22 | 22 │ └── ../seobeo |
| 23 ## Building | 23 │ ├── s_network.c |
| 24 │ ├── s_web.c | |
| 25 │ ├── s_http_client.c | |
| 26 │ └── s_ssl.c | |
| 27 ├── Frontend | |
| 28 │ └── src | |
| 29 │ ├── main.tsx | |
| 30 │ ├── components | |
| 31 │ │ ├── app.tsx | |
| 32 │ │ ├── directory-browser.tsx | |
| 33 │ │ ├── graph.tsx | |
| 34 │ │ ├── header.tsx | |
| 35 │ │ ├── footer.tsx | |
| 36 │ │ ├── theme.tsx | |
| 37 │ │ └── repo-browser.tsx | |
| 38 │ ├── index.html | |
| 39 │ ├── index.css | |
| 40 │ ├── base.css | |
| 41 │ └── custom pencil, panda, and icon assets | |
| 42 ├── Build | |
| 43 │ ├── BUILD | |
| 44 │ ├── ../gui_ze/gui_ze.bzl | |
| 45 │ ├── ../markdown_converter | |
| 46 │ └── ../third_party/highlight | |
| 47 └── Operations | |
| 48 └── deploy.sh | |
| 49 ``` | |
| 50 | |
| 51 `repo-browser.tsx` is an older standalone browser implementation. The active | |
| 52 entry point is `main.tsx`, which renders `app.tsx`; `app.tsx` embeds | |
| 53 `directory-browser.tsx`. | |
| 54 | |
| 55 ## Runtime topology | |
| 56 | |
| 57 ```text | |
| 58 Browser | |
| 59 | | |
| 60 | HTTPS | |
| 61 v | |
| 62 nginx | |
| 63 | | |
| 64 | HTTP :6970 | |
| 65 v | |
| 66 hg_web_server (main.c + Seobeo) | |
| 67 | | |
| 68 | HTTP :4444 | |
| 69 v | |
| 70 hg serve (Zenbu Mercurial repository) | |
| 71 ``` | |
| 72 | |
| 73 The C server owns the public routes. It serves the application shell and | |
| 74 assets, translates browser API requests into `hg serve` requests, and streams | |
| 75 Mercurial wire-protocol traffic without routing bundle data through the normal | |
| 76 buffered HTTP response path. | |
| 77 | |
| 78 ## Request flows | |
| 79 | |
| 80 ### Application shell | |
| 81 | |
| 82 ```text | |
| 83 GET /, /directories, or /graph | |
| 84 -> GetReactHome | |
| 85 -> hg-web/src/index.html | |
| 86 -> /page.js | |
| 87 -> src/main.tsx | |
| 88 -> components/app.tsx | |
| 89 ``` | |
| 90 | |
| 91 ### Repository browser | |
| 92 | |
| 93 ```text | |
| 94 directory-browser.tsx | |
| 95 -> GET /api/repo/list?path=... | |
| 96 -> ApiListDirectory | |
| 97 -> GET hg-serve/file/tip/<path>?style=json | |
| 98 | |
| 99 file or README selection | |
| 100 -> GET /api/repo/file?path=... | |
| 101 -> ApiGetFile | |
| 102 -> GET hg-serve/raw-file/tip/<path> | |
| 103 -> highlight.js, markdown_converter WASM, or inline static preview | |
| 104 ``` | |
| 105 | |
| 106 Images, SVG, video, audio, and PDF files open in the forge preview modal. | |
| 107 Unknown binary files retain a download link. The raw file API supplies explicit | |
| 108 MIME types, `nosniff`, inline disposition for supported previews, and sandboxed | |
| 109 SVG responses. | |
| 110 | |
| 111 ### Commit graph | |
| 112 | |
| 113 ```text | |
| 114 graph.tsx | |
| 115 -> GET /api/graph/<revision>?graphtop=...&style=json | |
| 116 -> ApiGetGraph | |
| 117 -> GET hg-serve/graph/<revision>?... | |
| 118 -> React rows + custom pencil/panda canvas | |
| 119 | |
| 120 graph row selection | |
| 121 -> /changeset/<revision> | |
| 122 -> GET /api/changeset/<revision> | |
| 123 -> ApiGetChangeset | |
| 124 -> GET hg-serve/json-rev/<revision> | |
| 125 -> changeset metadata + rendered diff | |
| 126 ``` | |
| 127 | |
| 128 ### Mercurial clone, pull, and push | |
| 129 | |
| 130 ```text | |
| 131 Mercurial client | |
| 132 -> GET or POST /repo | |
| 133 -> StreamHgWireProtocol | |
| 134 -> hg serve /?cmd=... | |
| 135 -> binary-safe streamed response | |
| 136 ``` | |
| 137 | |
| 138 ## Route map | |
| 139 | |
| 140 | Method | Route | Owner | Purpose | | |
| 141 | --- | --- | --- | --- | | |
| 142 | `GET` | `/` | `GetReactHome` | Application shell | | |
| 143 | `GET` | `/directories` | `GetReactHome` | Legacy application-shell route | | |
| 144 | `GET` | `/directory` | `GetReactHome` | Repository browser application route | | |
| 145 | `GET` | `/graph` | `GetReactHome` | Commit graph application route | | |
| 146 | `GET` | `/changeset/:changeset_id` | `GetReactHome` | Changeset application route | | |
| 147 | `GET` | `/api/repo/list` | `ApiListDirectory` | Directory listing JSON | | |
| 148 | `GET` | `/api/repo/file` | `ApiGetFile` | Raw tracked file | | |
| 149 | `GET` | `/api/repo/readme` | `ApiGetReadme` | Directory README content | | |
| 150 | `GET` | `/api/graph/:graph_id` | `ApiGetGraph` | Mercurial graph JSON | | |
| 151 | `GET` | `/api/changeset/:changeset_id` | `ApiGetChangeset` | Changeset metadata and diff JSON | | |
| 152 | `GET`, `POST` | `/repo` | `StreamHgWireProtocol` | Mercurial wire protocol | | |
| 153 | |
| 154 ## Frontend ownership | |
| 155 | |
| 156 | File | Responsibility | | |
| 157 | --- | --- | | |
| 158 | `src/components/app.tsx` | Client-side routes, landing page, tabs, and history | | |
| 159 | `src/components/directory-browser.tsx` | Breadcrumbs, listings, prefetch, file modals, README rendering | | |
| 160 | `src/components/graph.tsx` | Graph fetching, pagination, canvas edges, panda nodes | | |
| 161 | `src/components/theme.tsx` | Stored light/dark preference and system-theme integration | | |
| 162 | `src/components/header.tsx` | Forge identity and theme control | | |
| 163 | `src/components/footer.tsx` | Shared footer | | |
| 164 | `src/index.css`, `src/base.css` | Custom visual language and layout | | |
| 165 | |
| 166 Keep the custom assets and visual language in this package. New forge screens | |
| 167 should reuse the existing CSS variables, typography, textures, and components | |
| 168 instead of introducing a generic design system. | |
| 169 | |
| 170 ## Build and local run | |
| 171 | |
| 172 Build the server and deployable bundle from the repository root: | |
| 24 | 173 |
| 25 ```bash | 174 ```bash |
| 26 bazel build //hg-web:hg_web | 175 bazel build //hg-web:hg_web_server |
| 27 ``` | 176 bazel build //hg-web:hg_web_server_bundle |
| 28 | 177 bazel test //hg-web:tests |
| 29 ## API Endpoints | 178 bazel test //markdown_converter/tests:markdown_to_html_test |
| 30 | 179 bazel test //seobeo/tests:all |
| 31 The C server (`main.c`) provides: | 180 ``` |
| 32 | 181 |
| 33 - `GET /api/repo/list?path=` - List directory contents | 182 `//hg-web:tests` creates a temporary two-commit Mercurial repository and runs |
| 34 - `GET /api/repo/file?path=` - Fetch file contents | 183 the application in pinned Chromium through Playwright. It covers shell routes, |
| 184 files and README rendering, graph and changeset navigation, browser history, | |
| 185 console and page errors, API validation, Mercurial wire protocol, Markdown | |
| 186 script escaping, static assets, and backend outages. The test invokes the | |
| 187 workspace Mercurial CLI with an isolated configuration and home directory. | |
| 188 | |
| 189 Build and run the complete local stack with one Bazel command: | |
| 190 | |
| 191 ```bash | |
| 192 bazel run //hg-web:dev | |
| 193 ``` | |
| 194 | |
| 195 This starts `hg serve` on `127.0.0.1:4444` and `hg_web_server` on port `6970`. | |
| 196 Stopping the Bazel target stops both child processes. | |
| 197 | |
| 198 The bundle contains `hg_web_server` and `hg-web/src/`, including generated | |
| 199 `page.js`, markdown WASM, highlight.js, styles, and image assets. | |
| 200 | |
| 201 ## Deployment contract | |
| 202 | |
| 203 The expected production layout is: | |
| 204 | |
| 205 ```text | |
| 206 nginx | |
| 207 -> hg_web_server.service | |
| 208 -> /opt/hg_web_server_bundle_active/hg_web_server | |
| 209 -> working directory: /opt/hg_web_server_bundle_active | |
| 210 -> hg serve service on 127.0.0.1:4444 | |
| 211 ``` | |
| 212 | |
| 213 `deploy.sh` builds an optimized bundle into a revisioned release directory, | |
| 214 atomically repoints `/opt/hg_web_server_bundle_active`, restarts | |
| 215 `hg_web_server.service`, and checks `http://127.0.0.1:6970/`. A failed restart | |
| 216 or health check restores the previous release and restarts it. The service, | |
| 217 release root, active path, health URL, user, and group can be overridden with | |
| 218 environment variables. | |
| 219 | |
| 220 ## Forge capability tree | |
| 221 | |
| 222 ```text | |
| 223 Zenbu Forge | |
| 224 ├── Repository | |
| 225 │ ├── File and directory browsing available | |
| 226 │ ├── Syntax highlighting available | |
| 227 │ ├── README rendering available | |
| 228 │ ├── Commit graph available | |
| 229 │ ├── Changeset detail and diff available | |
| 230 │ ├── Branches, bookmarks, and tags planned | |
| 231 │ ├── File history and blame planned | |
| 232 │ └── Search planned | |
| 233 ├── Collaboration | |
| 234 │ ├── Authentication and authorization planned | |
| 235 │ ├── Changeset review planned | |
| 236 │ ├── Issues planned | |
| 237 │ └── Releases and artifacts planned | |
| 238 └── Automation | |
| 239 ├── Mercurial incoming/changegroup hook planned | |
| 240 ├── Durable SQLite job queue planned | |
| 241 ├── Isolated Bazel runner planned | |
| 242 ├── Live logs and job status API planned | |
| 243 ├── Forge status and log screens planned | |
| 244 ├── Artifact retention planned | |
| 245 └── Atomic deploy, health check, rollback available | |
| 246 ``` | |
| 247 | |
| 248 ## Automation data flow | |
| 249 | |
| 250 The Actions-like subsystem should extend the existing server rather than | |
| 251 replace it: | |
| 252 | |
| 253 ```text | |
| 254 hg push | |
| 255 -> Mercurial hook records repository + revision | |
| 256 -> small enqueue command writes a SQLite job | |
| 257 -> runner service claims one queued job | |
| 258 -> isolated shared checkout updates to the exact revision | |
| 259 -> Bazel build and test steps stream logs | |
| 260 -> job result and artifacts are recorded | |
| 261 -> hg-web status API exposes the result | |
| 262 -> custom React screens render runs, steps, logs, and artifacts | |
| 263 -> successful protected jobs may call atomic deployment | |
| 264 ``` | |
| 265 | |
| 266 Start with one runner on the same host. Keep the hook fast, never execute build | |
| 267 steps inside the Mercurial request, and make the queue durable before adding | |
| 268 parallel or remote runners. | |
| 269 | |
| 270 ## Safe extension order | |
| 271 | |
| 272 1. Add branches, bookmarks, tags, file history, blame, and search. | |
| 273 2. Add the hook, SQLite queue, single runner, and retained logs. | |
| 274 3. Add run/status/log pages using the existing custom UI. | |
| 275 4. Add authentication and authorization before accepting public pushes or | |
| 276 user-defined automation. | |
| 277 | |
| 278 ## Invariants | |
| 279 | |
| 280 - Keep public application code on Seobeo APIs. | |
| 281 - Decode and validate every path before forwarding it to Mercurial. | |
| 282 - Keep `/repo` binary-safe; bundle data can contain null bytes. | |
| 283 - Do not buffer large wire-protocol responses through the regular HTTP client. | |
| 284 - Keep backend route names synchronized with frontend fetch and navigation code. | |
| 285 - Preserve accurate status codes, content lengths, and content types. | |
| 286 - Keep secrets in service-owned environment files, not in source or job logs. |