Skip to content

Where people and agents ship software together. The open-source git platform for the whole job: issues, agents, checks and deploys to the edge.

Commit

Prettier over the repository (Closes #165)

npm run format -- . with .prettierrc.json, and nothing else. Test fixtures (fixtures/, *.fixtures.json, *_fixtures.json) stay byte for byte as captured, and guides/self-hosted-runners.mdx is left out because Prettier's MDX printer rewrites it on every run; both are now in .prettierignore, so npm run format:check -- . passes.

G1t-Session:
ses_01m57b7r6jew3aqgyfmhw6yah6
syntaqxcommitted Parent9420f43Browse files
300 files+5122−4552204 files not counted0/300 viewed
+18−18
2525 These are the files to upload to Stripe and similar services. The site serves
2626 its own copies from `apps/web/public` and `apps/docs/public`.
2727
28−| File | Size | Use |
29−| --- | --- | --- |
30−| `icon-512.png` | 512×512, dark square | Stripe branding icon (square, at least 128px), Slack, GitHub app avatars |
31−| `icon-1024.png` | 1024×1024, dark square | App stores and anywhere asking for a large square icon |
32−| `icon-transparent-1024.png` | 1024×1024, transparent | Placing the icon on a dark surface of your own |
33−| `logo-on-dark.png` | 1056×642, dark background | Stripe branding logo (wide), docs and decks on dark |
34−| `logo-on-light.png` | 1056×642, white background | Invoices, receipts and anywhere the background is light |
28+| File | Size | Use |
29+| --------------------------- | -------------------------- | ------------------------------------------------------------------------ |
30+| `icon-512.png` | 512×512, dark square | Stripe branding icon (square, at least 128px), Slack, GitHub app avatars |
31+| `icon-1024.png` | 1024×1024, dark square | App stores and anywhere asking for a large square icon |
32+| `icon-transparent-1024.png` | 1024×1024, transparent | Placing the icon on a dark surface of your own |
33+| `logo-on-dark.png` | 1056×642, dark background | Stripe branding logo (wide), docs and decks on dark |
34+| `logo-on-light.png` | 1056×642, white background | Invoices, receipts and anywhere the background is light |
3535
3636 ## Sources
3737
3838 `svg/` holds the source of every file above and of the site's favicons:
3939
40−| File | What it is |
41−| --- | --- |
42−| `svg/mark.svg` | The icon, the pixel 1, centred in a transparent square, for dark backgrounds (also `packages/theme/mark.svg`) |
43−| `svg/mark-on-light.svg` | The icon on transparent, for light backgrounds |
44−| `svg/mark-small.svg` | The 16px cut: each cell 2px, no gap |
45−| `svg/icon-square.svg` | The icon on a full-bleed dark square, 1024 box on 100-unit cells (`icon-512.png`, `icon-1024.png`) |
46−| `svg/icon-rounded.svg` | The icon on a rounded dark tile, the 256px cut (`brand/g1t-mark.*`) |
47−| `svg/icon-padded.svg` | The icon with room for a circle crop, the 512px cut (`icon-512.png` in the apps; `apple-touch-icon.png` and `icon-192.png` are cut the same way at their own sizes) |
48−| `svg/favicon.svg` | The 16px cut with no tile, coloured for a light or dark browser (`favicon.svg` in the apps and `packages/theme`) |
49−| `svg/logo.svg`, `svg/logo-on-light.svg` | The wordmark, transparent and cropped to its ink, for dark and light backgrounds |
50−| `svg/logo-dark-bg.svg`, `svg/logo-light-bg.svg` | The wordmark with padding and a background, on 40px cells |
40+| File | What it is |
41+| ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
42+| `svg/mark.svg` | The icon, the pixel 1, centred in a transparent square, for dark backgrounds (also `packages/theme/mark.svg`) |
43+| `svg/mark-on-light.svg` | The icon on transparent, for light backgrounds |
44+| `svg/mark-small.svg` | The 16px cut: each cell 2px, no gap |
45+| `svg/icon-square.svg` | The icon on a full-bleed dark square, 1024 box on 100-unit cells (`icon-512.png`, `icon-1024.png`) |
46+| `svg/icon-rounded.svg` | The icon on a rounded dark tile, the 256px cut (`brand/g1t-mark.*`) |
47+| `svg/icon-padded.svg` | The icon with room for a circle crop, the 512px cut (`icon-512.png` in the apps; `apple-touch-icon.png` and `icon-192.png` are cut the same way at their own sizes) |
48+| `svg/favicon.svg` | The 16px cut with no tile, coloured for a light or dark browser (`favicon.svg` in the apps and `packages/theme`) |
49+| `svg/logo.svg`, `svg/logo-on-light.svg` | The wordmark, transparent and cropped to its ink, for dark and light backgrounds |
50+| `svg/logo-dark-bg.svg`, `svg/logo-light-bg.svg` | The wordmark with padding and a background, on 40px cells |
5151
5252 `favicon.ico` in the apps holds the 16, 32 and 48px cuts of the icon on a
5353 rounded dark tile. The pixels are squares, so no file needs a font.
+2−2
7070 environment:
7171 name: production
7272 deployment: false
73− timeout-minutes: 60 # the most g1t's own machines run a job
73+ timeout-minutes: 60 # the most g1t's own machines run a job
7474 steps:
7575 - uses: actions/checkout@v5
7676 # rust: the toolchain; desktop: the app's Cargo.lock's crates.io and
174174 environment:
175175 name: production
176176 deployment: false
177− timeout-minutes: 60 # the most g1t's own machines run a job
177+ timeout-minutes: 60 # the most g1t's own machines run a job
178178 steps:
179179 - uses: actions/checkout@v5
180180 - name: Cache keys
+6−0
77 .react-router/
88 *.lock
99 package-lock.json
10+# Test fixtures: kept byte for byte as they were captured.
11+**/fixtures/
12+*.fixtures.json
13+*_fixtures.json
14+# Prettier's MDX printer changes this page again on every run.
15+apps/docs/src/content/docs/guides/self-hosted-runners.mdx
+1−1
11 {
2− "editor.formatOnSave": true
2+ "editor.formatOnSave": true
33 }
+23−23
1010 A pull request that changes what someone can do, see or call changes the
1111 docs in the same pull request:
1212
13−| If you change | Update |
14−| --- | --- |
15−| Something a person does on g1t.sh | The guide for it in `apps/docs/src/content/docs/guides/` |
16−| An API route, a field, or an MCP tool | `apps/api/src/operations.rs` descriptions (they feed the OpenAPI document and the API reference), the example and notes for it in `apps/api/src/reference.json`, `reference/mcp.md`, and any guide that shows the call. Then refresh the docs' copy of the OpenAPI document with `G1T_WRITE_OPENAPI=1 cargo test -p g1t-api openapi`; `cargo test` fails until you do. |
17−| What coding agents are told about g1t | `guides/bring-your-own-agent.mdx`, `guides/claude-code-plugin.md`, the plugin's skills in `plugins/claude-code/`, and `apps/web/public/llms.txt` |
18−| The Claude Code plugin's files (`plugins/claude-code/`, except `test/`) | Its version, the same in `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`: Claude Code updates an installed plugin only when it changes. On main, `plugins-release.yml` publishes it to `flagon-io/g1t-plugins`, and refuses a changed plugin with a version already published. Never commit to g1t-plugins itself. |
19−| Settings, limits or prices | The page that names them, and the table it is in |
20−| A new feature | A section in the guide that owns it, linked from the docs home if it is a new task |
21−| How g1t is put together: a service, a binding, a store, an event route, the path of a request | Its page in the docs' Architecture section (`apps/docs/src/content/docs/architecture/`), and its diagram in `apps/docs/src/diagrams/architecture.ts`. [How g1t ships](https://docs.g1t.sh/architecture/shipping/#keeping-this-section-true) says which page covers what. |
13+| If you change | Update |
14+| --------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
15+| Something a person does on g1t.sh | The guide for it in `apps/docs/src/content/docs/guides/` |
16+| An API route, a field, or an MCP tool | `apps/api/src/operations.rs` descriptions (they feed the OpenAPI document and the API reference), the example and notes for it in `apps/api/src/reference.json`, `reference/mcp.md`, and any guide that shows the call. Then refresh the docs' copy of the OpenAPI document with `G1T_WRITE_OPENAPI=1 cargo test -p g1t-api openapi`; `cargo test` fails until you do. |
17+| What coding agents are told about g1t | `guides/bring-your-own-agent.mdx`, `guides/claude-code-plugin.md`, the plugin's skills in `plugins/claude-code/`, and `apps/web/public/llms.txt` |
18+| The Claude Code plugin's files (`plugins/claude-code/`, except `test/`) | Its version, the same in `.claude-plugin/plugin.json` and `.claude-plugin/marketplace.json`: Claude Code updates an installed plugin only when it changes. On main, `plugins-release.yml` publishes it to `flagon-io/g1t-plugins`, and refuses a changed plugin with a version already published. Never commit to g1t-plugins itself. |
19+| Settings, limits or prices | The page that names them, and the table it is in |
20+| A new feature | A section in the guide that owns it, linked from the docs home if it is a new task |
21+| How g1t is put together: a service, a binding, a store, an event route, the path of a request | Its page in the docs' Architecture section (`apps/docs/src/content/docs/architecture/`), and its diagram in `apps/docs/src/diagrams/architecture.ts`. [How g1t ships](https://docs.g1t.sh/architecture/shipping/#keeping-this-section-true) says which page covers what. |
2222
2323 The style, in short: plain sentences, second person, no marketing words,
2424 sentence-case headings, a numbered list for steps, a table for options, and
200200 its cache is keyed by that digest (`zigbuild` from `ci-cache.mjs keys`)
201201 rather than by this machine's `rustc`.
202202
203−| Entry | Key | Saved by | Restored by |
204−| --- | --- | --- | --- |
205−| npm's downloads | `npm-full-<os>-<package-lock.json>` | Caches (`npm`) | every npm install |
206−| Crates and their index | `cargo-crates-<os>-<deps>` | CI Rust (`cargo fetch` of the whole lockfile) | Deploy, the runner release |
207−| The test build | `cargo-test-<os>-<rust>-<deps>` | CI Rust | CI Rust on pull requests |
208−| Workers' builds | `cargo-workers-<os>-<rust>-<group>-<deps>` | Deploy | Deploy |
209−| The runner's image build | `runner-musl-<os>-<rust>-<deps>` | Deploy | Deploy |
210−| worker-build and its tools | `worker-build-…`, `worker-build-tools-…` | Deploy | Deploy |
211−| Compiled crates | sccache's, one per crate | every Rust job | every Rust job |
212−| The desktop app's check | `desktop-check-<os>-<rust>-<desktop deps>` | CI desktop | CI desktop on pull requests |
213−| apt for Tauri | `apt-tauri-<os>-<scripts/apt-install.sh>` | CI desktop | the desktop release |
214−| The runner release | `runner-release-<os>-<target>-<rust>-<deps>`, zig | Caches (`runner`) | the runner release |
215−| The desktop release | `desktop-release-linux-…`, `desktop-release-windows-…`, `xwin-…`, `apt-tauri-windows-…` | Caches (`desktop-linux`, `desktop-windows`) | the desktop release |
216−| The CLI release | `cli-release-<os>-<zigbuild>-<deps>` (`target/zig`, every platform) | Caches (`cli`), built whole | the CLI release |
203+| Entry | Key | Saved by | Restored by |
204+| -------------------------- | --------------------------------------------------------------------------------------- | --------------------------------------------- | --------------------------- |
205+| npm's downloads | `npm-full-<os>-<package-lock.json>` | Caches (`npm`) | every npm install |
206+| Crates and their index | `cargo-crates-<os>-<deps>` | CI Rust (`cargo fetch` of the whole lockfile) | Deploy, the runner release |
207+| The test build | `cargo-test-<os>-<rust>-<deps>` | CI Rust | CI Rust on pull requests |
208+| Workers' builds | `cargo-workers-<os>-<rust>-<group>-<deps>` | Deploy | Deploy |
209+| The runner's image build | `runner-musl-<os>-<rust>-<deps>` | Deploy | Deploy |
210+| worker-build and its tools | `worker-build-…`, `worker-build-tools-…` | Deploy | Deploy |
211+| Compiled crates | sccache's, one per crate | every Rust job | every Rust job |
212+| The desktop app's check | `desktop-check-<os>-<rust>-<desktop deps>` | CI desktop | CI desktop on pull requests |
213+| apt for Tauri | `apt-tauri-<os>-<scripts/apt-install.sh>` | CI desktop | the desktop release |
214+| The runner release | `runner-release-<os>-<target>-<rust>-<deps>`, zig | Caches (`runner`) | the runner release |
215+| The desktop release | `desktop-release-linux-…`, `desktop-release-windows-…`, `xwin-…`, `apt-tauri-windows-…` | Caches (`desktop-linux`, `desktop-windows`) | the desktop release |
216+| The CLI release | `cli-release-<os>-<zigbuild>-<deps>` (`target/zig`, every platform) | Caches (`cli`), built whole | the CLI release |
217217
218218 To see whether a change helped, read a run's cache steps: `Cache restored
219219 from key` names the entry (the key itself is a hit; another is a start),
+46−46
119119
120120 ## Layout
121121
122−| Path | What it is | Language |
123−| --- | --- | --- |
124−| `apps/web` | The site: server-rendered React on a Worker. Holds no data. | TypeScript |
125−| `apps/docs` | The documentation site, with the API explorer. | TypeScript |
126−| `apps/api` | REST API and MCP server. | Rust |
127−| `apps/desktop` | The desktop app (Tauri), with a runner inside. | Rust, TypeScript |
128−| `apps/mobile` | The phone app (Expo). | TypeScript |
129−| `apps/status` | The status page at `status.g1t.sh`. | TypeScript |
130−| `apps/sudo` | g1t's own staff console. | TypeScript |
131−| `services/identity` | Accounts, workspaces, sessions, keys, tokens and invites. | Rust |
132−| `services/repos` | Repository registry, contents, forks, diffs, landing, git over HTTPS. | Rust |
133−| `services/work` | Work items, pull requests, reviews, check runs, agent sessions, claims and the merge queue. | Rust |
134−| `services/events` | The event bus and its log. | Rust |
135−| `services/search` | Site-wide search and Explore. | Rust |
136−| `services/billing` | Usage, the price book, limits, invoices and payments. | Rust |
137−| `services/actions` | Workflows, runs, caches and self-hosted runners. | Rust |
138−| `services/security` | Push protection findings, history scanning and dependency updates. | Rust |
139−| `services/integrations` | AI providers, Ask, alerts, trackers and the GitHub App. | Rust |
140−| `services/webhooks` | Webhook deliveries. | Rust |
141−| `services/packages` | The package registries and container images. | Rust |
142−| `services/runner` | Starts sandboxes for workflow jobs, builds and the merge queue. | TypeScript |
143−| `services/projects` | Projects: what a workspace builds and runs, and where its code lives. | TypeScript |
144−| `services/deployments` | Builds, previews and production on `g1t.page`. | TypeScript |
145−| `services/pages` | Serves every app deployed on `g1t.page`, and custom domains. | TypeScript |
146−| `services/telemetry` | Observability: OpenTelemetry ingest, logs, traces, metrics and errors. | TypeScript |
147−| `services/chat` | Channels, direct messages, threads and their live sockets. | TypeScript |
148−| `services/artifacts` | Docs: their spaces, sharing and live editing. | TypeScript |
149−| `services/notify` | Notifications: each person's feed, live counts and browser push. | TypeScript |
150−| `services/og` | Social cards at `og.g1t.sh`: a PNG per page, showing only what anyone may see. | TypeScript |
151−| `crates/g1t` | The `g1t` command line. | Rust |
152−| `crates/runner` | The program inside a sandbox, and the self-hosted runner: runs a workflow job or a build and reports back. | Rust |
153−| `crates/contracts` | Types and service interfaces for the Rust services. | Rust |
154−| `crates/kit` | Plumbing shared by Rust services on Workers. | Rust |
155−| `crates/rules` | The rules engine for rulesets on branches and tags. | Rust |
156−| `crates/blobstore` | Object storage: R2 on Cloudflare, any S3-compatible store self-hosted. | Rust |
157−| `crates/actions` | Reads workflows and evaluates their expressions. | Rust |
158−| `crates/scan` | Secret and lockfile scanning, shared by services. | Rust |
159−| `crates/secrets` | Secrets at rest and signatures. | Rust |
160−| `crates/sshd` | Git over SSH, bridged to Cloudflare Artifacts. Not deployed. | Rust |
161−| `packages/contracts` | The same interfaces for TypeScript callers. | TypeScript |
162−| `packages/theme` | Design tokens and the logo, shared by the site and the docs. | CSS |
163−| `plugins/claude-code` | g1t's Claude Code plugin: hooks, skills and commands, published to `flagon-io/g1t-plugins` on every change. | JavaScript |
164−| `plugins/codex` | Codex plugin: MCP server and work coordination skill, published to `flagon-io/g1t-plugins`. | JSON / Markdown |
165−| `plugins/other-harnesses` | The AGENTS.md snippet for Codex, Cursor and other harnesses. | Markdown |
166−| `deploy` | `stack.jsonc`, every deployable part and its resources; `self-host`, the Docker Compose version. | JSON, Docker Compose |
122+| Path | What it is | Language |
123+| ------------------------- | ----------------------------------------------------------------------------------------------------------- | -------------------- |
124+| `apps/web` | The site: server-rendered React on a Worker. Holds no data. | TypeScript |
125+| `apps/docs` | The documentation site, with the API explorer. | TypeScript |
126+| `apps/api` | REST API and MCP server. | Rust |
127+| `apps/desktop` | The desktop app (Tauri), with a runner inside. | Rust, TypeScript |
128+| `apps/mobile` | The phone app (Expo). | TypeScript |
129+| `apps/status` | The status page at `status.g1t.sh`. | TypeScript |
130+| `apps/sudo` | g1t's own staff console. | TypeScript |
131+| `services/identity` | Accounts, workspaces, sessions, keys, tokens and invites. | Rust |
132+| `services/repos` | Repository registry, contents, forks, diffs, landing, git over HTTPS. | Rust |
133+| `services/work` | Work items, pull requests, reviews, check runs, agent sessions, claims and the merge queue. | Rust |
134+| `services/events` | The event bus and its log. | Rust |
135+| `services/search` | Site-wide search and Explore. | Rust |
136+| `services/billing` | Usage, the price book, limits, invoices and payments. | Rust |
137+| `services/actions` | Workflows, runs, caches and self-hosted runners. | Rust |
138+| `services/security` | Push protection findings, history scanning and dependency updates. | Rust |
139+| `services/integrations` | AI providers, Ask, alerts, trackers and the GitHub App. | Rust |
140+| `services/webhooks` | Webhook deliveries. | Rust |
141+| `services/packages` | The package registries and container images. | Rust |
142+| `services/runner` | Starts sandboxes for workflow jobs, builds and the merge queue. | TypeScript |
143+| `services/projects` | Projects: what a workspace builds and runs, and where its code lives. | TypeScript |
144+| `services/deployments` | Builds, previews and production on `g1t.page`. | TypeScript |
145+| `services/pages` | Serves every app deployed on `g1t.page`, and custom domains. | TypeScript |
146+| `services/telemetry` | Observability: OpenTelemetry ingest, logs, traces, metrics and errors. | TypeScript |
147+| `services/chat` | Channels, direct messages, threads and their live sockets. | TypeScript |
148+| `services/artifacts` | Docs: their spaces, sharing and live editing. | TypeScript |
149+| `services/notify` | Notifications: each person's feed, live counts and browser push. | TypeScript |
150+| `services/og` | Social cards at `og.g1t.sh`: a PNG per page, showing only what anyone may see. | TypeScript |
151+| `crates/g1t` | The `g1t` command line. | Rust |
152+| `crates/runner` | The program inside a sandbox, and the self-hosted runner: runs a workflow job or a build and reports back. | Rust |
153+| `crates/contracts` | Types and service interfaces for the Rust services. | Rust |
154+| `crates/kit` | Plumbing shared by Rust services on Workers. | Rust |
155+| `crates/rules` | The rules engine for rulesets on branches and tags. | Rust |
156+| `crates/blobstore` | Object storage: R2 on Cloudflare, any S3-compatible store self-hosted. | Rust |
157+| `crates/actions` | Reads workflows and evaluates their expressions. | Rust |
158+| `crates/scan` | Secret and lockfile scanning, shared by services. | Rust |
159+| `crates/secrets` | Secrets at rest and signatures. | Rust |
160+| `crates/sshd` | Git over SSH, bridged to Cloudflare Artifacts. Not deployed. | Rust |
161+| `packages/contracts` | The same interfaces for TypeScript callers. | TypeScript |
162+| `packages/theme` | Design tokens and the logo, shared by the site and the docs. | CSS |
163+| `plugins/claude-code` | g1t's Claude Code plugin: hooks, skills and commands, published to `flagon-io/g1t-plugins` on every change. | JavaScript |
164+| `plugins/codex` | Codex plugin: MCP server and work coordination skill, published to `flagon-io/g1t-plugins`. | JSON / Markdown |
165+| `plugins/other-harnesses` | The AGENTS.md snippet for Codex, Cursor and other harnesses. | Markdown |
166+| `deploy` | `stack.jsonc`, every deployable part and its resources; `self-host`, the Docker Compose version. | JSON, Docker Compose |
167167
168168 Each service is its own Worker, and each one that keeps data has its own
169169 database. They call each other through service bindings and react to each
207207
208208 1. Create the resources each part needs: D1 databases, queues, KV
209209 namespaces, R2 buckets and the Cloudflare Artifacts namespace (`npx wrangler d1
210− create <name>`, `npx wrangler queues create <name>`, and so on), and set
210+create <name>`, `npx wrangler queues create <name>`, and so on), and set
211211 each part's secrets. `deploy/stack.jsonc` lists them all.
212212 2. Put your own `account_id`, database ids and hostnames in each
213213 `wrangler.jsonc`.
+15−15
3535
3636 ## Inputs
3737
38−| Input | Default | |
39−| --- | --- | --- |
40−| `project` | The repository's one project with Deployments on | The project's slug. Needed when the repository has several. |
41−| `root-dir` | The project's setting | Where the project is in the checkout. |
42−| `build-command` | The project's setting, else what the build finds | What builds it. |
43−| `output-dir` | The project's setting, else the folder the framework writes, else the first of `dist`, `build`, `out`, `public`, `_site`, `.output/public` | The folder a static build writes. |
44−| `build-as` | The project's setting, else `auto` | What it is built as: `auto`, `static`, `workers` or `docker`. A container is built with the `docker` on the job's `PATH`. |
45−| `dockerfile` | The project's setting, else `Dockerfile` or `Containerfile` | The Dockerfile a container is built from, relative to the project. |
46−| `sha` | The run's commit | The commit this is a build of, for its `g1t / deploy` check. |
47−| `token` | `${{ github.token }}` | The job's own token. It needs `deployments: write`; any other token is refused. |
38+| Input | Default | |
39+| --------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- |
40+| `project` | The repository's one project with Deployments on | The project's slug. Needed when the repository has several. |
41+| `root-dir` | The project's setting | Where the project is in the checkout. |
42+| `build-command` | The project's setting, else what the build finds | What builds it. |
43+| `output-dir` | The project's setting, else the folder the framework writes, else the first of `dist`, `build`, `out`, `public`, `_site`, `.output/public` | The folder a static build writes. |
44+| `build-as` | The project's setting, else `auto` | What it is built as: `auto`, `static`, `workers` or `docker`. A container is built with the `docker` on the job's `PATH`. |
45+| `dockerfile` | The project's setting, else `Dockerfile` or `Containerfile` | The Dockerfile a container is built from, relative to the project. |
46+| `sha` | The run's commit | The commit this is a build of, for its `g1t / deploy` check. |
47+| `token` | `${{ github.token }}` | The job's own token. It needs `deployments: write`; any other token is refused. |
4848
4949 ## Outputs
5050
51−| Output | |
52−| --- | --- |
53−| `url` | Where the app is served. |
54−| `deployment-id` | The build's id, `dpl_…`. |
55−| `kind` | `production` or `preview`. |
51+| Output | |
52+| --------------- | -------------------------- |
53+| `url` | Where the app is served. |
54+| `deployment-id` | The build's id, `dpl_…`. |
55+| `kind` | `production` or `preview`. |
5656
5757 ## How it works
5858
+33−33
1919
2020 ## Inputs
2121
22−| Input | Default | |
23−| --- | --- | --- |
24−| `root-dir` | The checkout | Where the project is in the checkout. |
25−| `build-command` | None | A build command of your own, as `g1t/deploy` takes it. |
26−| `output-dir` | None | An output folder of your own, as `g1t/deploy` takes it. |
27−| `build-as` | `auto` | What it is built as: `auto`, `static`, `workers` or `docker` (Container), as `g1t/deploy` takes it. |
28−| `dockerfile` | None | A Dockerfile's path of your own, as `g1t/deploy` takes it. |
22+| Input | Default | |
23+| --------------- | ------------ | --------------------------------------------------------------------------------------------------- |
24+| `root-dir` | The checkout | Where the project is in the checkout. |
25+| `build-command` | None | A build command of your own, as `g1t/deploy` takes it. |
26+| `output-dir` | None | An output folder of your own, as `g1t/deploy` takes it. |
27+| `build-as` | `auto` | What it is built as: `auto`, `static`, `workers` or `docker` (Container), as `g1t/deploy` takes it. |
28+| `dockerfile` | None | A Dockerfile's path of your own, as `g1t/deploy` takes it. |
2929
3030 ## Outputs
3131
32−| Output | |
33−| --- | --- |
34−| `kind` | `workers` (a `wrangler.jsonc`, `wrangler.json` or `wrangler.toml`, a framework's Cloudflare adapter, or a Node.js server run as a Worker), `static` (a site a build writes), `html` (the files as they are), `container` (a server that is not run as a Worker, a framework set up to need a server, or a `Dockerfile` with nothing else to serve) or `none` (nothing to serve). |
35−| `framework` | The framework it is built with, from the table below; `node` for a Node.js server run as a Worker; for a container without one, `dockerfile`, or the server g1t writes a Dockerfile for (`node`, `django`, `flask`, `fastapi`, `python`, `go`, `rails`, `rack`, `laravel`, `php`). Empty when there is none. |
36−| `dockerfile` | A container's own Dockerfile, relative to the project. Empty when g1t writes one, and for anything that is not a container. |
37−| `port` | The port a container listens on: its Dockerfile's `EXPOSE`, else `8080`. |
38−| `entry` | For a Node.js server run as a Worker, the file that starts it, relative to the project. Empty for anything else. |
39−| `install` | How dependencies are installed, from the lockfile: `npm ci`, `pnpm install --frozen-lockfile`, and so on, and `bundle install` for Jekyll. Empty when there is nothing to install. |
40−| `build` | What builds it: your command, the package's `build` script (`npm run build`), the framework's own command, or `wrangler deploy --dry-run` for Workers. Empty when nothing does. |
41−| `output-dir` | The folder served, relative to the project (`.` for the project itself): yours, a Workers project's assets directory, the folder the framework writes, or the first of `dist`, `build`, `out`, `public`, `_site`, `.output/public` that exists. Empty when a build has yet to write it, as for a Cloudflare adapter's Worker. |
32+| Output | |
33+| ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
34+| `kind` | `workers` (a `wrangler.jsonc`, `wrangler.json` or `wrangler.toml`, a framework's Cloudflare adapter, or a Node.js server run as a Worker), `static` (a site a build writes), `html` (the files as they are), `container` (a server that is not run as a Worker, a framework set up to need a server, or a `Dockerfile` with nothing else to serve) or `none` (nothing to serve). |
35+| `framework` | The framework it is built with, from the table below; `node` for a Node.js server run as a Worker; for a container without one, `dockerfile`, or the server g1t writes a Dockerfile for (`node`, `django`, `flask`, `fastapi`, `python`, `go`, `rails`, `rack`, `laravel`, `php`). Empty when there is none. |
36+| `dockerfile` | A container's own Dockerfile, relative to the project. Empty when g1t writes one, and for anything that is not a container. |
37+| `port` | The port a container listens on: its Dockerfile's `EXPOSE`, else `8080`. |
38+| `entry` | For a Node.js server run as a Worker, the file that starts it, relative to the project. Empty for anything else. |
39+| `install` | How dependencies are installed, from the lockfile: `npm ci`, `pnpm install --frozen-lockfile`, and so on, and `bundle install` for Jekyll. Empty when there is nothing to install. |
40+| `build` | What builds it: your command, the package's `build` script (`npm run build`), the framework's own command, or `wrangler deploy --dry-run` for Workers. Empty when nothing does. |
41+| `output-dir` | The folder served, relative to the project (`.` for the project itself): yours, a Workers project's assets directory, the folder the framework writes, or the first of `dist`, `build`, `out`, `public`, `_site`, `.output/public` that exists. Empty when a build has yet to write it, as for a Cloudflare adapter's Worker. |
4242
4343 When `kind` is `none`, the step's log says what to change or add, such as
4444 a `Dockerfile`. [Docker deployments](https://docs.g1t.sh/guides/deployments/#docker-deployments)
4646
4747 ## Frameworks
4848
49−| `framework` | Found by | Serves |
50−| --- | --- | --- |
51−| `vite`, `vite-react`, `vite-vue`, `vite-svelte`, `vite-solid`, `vite-preact` | `vite`, and the framework's Vite plugin | `dist`, or `build.outDir` |
52−| `astro` | `astro` | `dist`, or `outDir`; a Worker with `@astrojs/cloudflare` |
53−| `nextjs` | `next` | `out` with `output: 'export'`; a Worker with `@opennextjs/cloudflare` and a `wrangler.jsonc` |
54−| `sveltekit` | `@sveltejs/kit` | `build` with `adapter-static`; a Worker with `adapter-cloudflare` |
55−| `nuxt` | `nuxt` | `.output/public`, from `nuxi generate` |
56−| `react-router`, `remix` | `@react-router/dev`, `@remix-run/dev` | `build/client` with `ssr: false` |
57−| `gatsby` | `gatsby` | `public` |
58−| `docusaurus` | `@docusaurus/core` | `build` |
59−| `eleventy` | `@11ty/eleventy` | `_site` |
60−| `angular` | `@angular/core` and `angular.json` | `dist/<project>/browser` |
61−| `create-react-app` | `react-scripts` | `build` |
62−| `hugo` | `hugo.toml`, or Hugo's `config.toml` | `public` |
63−| `jekyll` | `_config.yml` and a `Gemfile` | `_site` |
64−| `mdbook` | `book.toml` | `book` |
49+| `framework` | Found by | Serves |
50+| ---------------------------------------------------------------------------- | --------------------------------------- | -------------------------------------------------------------------------------------------- |
51+| `vite`, `vite-react`, `vite-vue`, `vite-svelte`, `vite-solid`, `vite-preact` | `vite`, and the framework's Vite plugin | `dist`, or `build.outDir` |
52+| `astro` | `astro` | `dist`, or `outDir`; a Worker with `@astrojs/cloudflare` |
53+| `nextjs` | `next` | `out` with `output: 'export'`; a Worker with `@opennextjs/cloudflare` and a `wrangler.jsonc` |
54+| `sveltekit` | `@sveltejs/kit` | `build` with `adapter-static`; a Worker with `adapter-cloudflare` |
55+| `nuxt` | `nuxt` | `.output/public`, from `nuxi generate` |
56+| `react-router`, `remix` | `@react-router/dev`, `@remix-run/dev` | `build/client` with `ssr: false` |
57+| `gatsby` | `gatsby` | `public` |
58+| `docusaurus` | `@docusaurus/core` | `build` |
59+| `eleventy` | `@11ty/eleventy` | `_site` |
60+| `angular` | `@angular/core` and `angular.json` | `dist/<project>/browser` |
61+| `create-react-app` | `react-scripts` | `build` |
62+| `hugo` | `hugo.toml`, or Hugo's `config.toml` | `public` |
63+| `jekyll` | `_config.yml` and a `Gemfile` | `_site` |
64+| `mdbook` | `book.toml` | `book` |
6565
6666 [What deploys](https://docs.g1t.sh/guides/deployments/#frameworks) has
6767 each one's build command. Your `build-command` and `output-dir` win over
+0−0

Binary or large file; its contents are not shown.

+54−54
11 {
2− "$schema": "../../node_modules/wrangler/config-schema.json",
3− "name": "g1t-api",
4− "account_id": "1e6f2cffa3f445920836e8ebe446bb58",
5− "compatibility_date": "2026-09-26",
6− "placement": { "mode": "off" },
7− "main": "build/index.js",
8− "build": { "command": "node ../../scripts/build-rust-worker.mjs" },
9− "workers_dev": false,
10− // One Worker, two hostnames: REST on api, MCP on mcp. Both are thin
11− // adapters over the same operations.
12− "routes": [
13− { "pattern": "api.g1t.sh", "custom_domain": true },
14− { "pattern": "mcp.g1t.sh", "custom_domain": true }
15− ],
16− "services": [
17− { "binding": "IDENTITY", "service": "g1t-identity" },
18− { "binding": "REPOS", "service": "g1t-repos" },
19− { "binding": "WORK", "service": "g1t-work" },
20− { "binding": "EVENTS", "service": "g1t-events" },
21− { "binding": "RUNNER", "service": "g1t-runner" },
22− { "binding": "BILLING", "service": "g1t-billing" },
23− { "binding": "INTEGRATIONS", "service": "g1t-integrations" },
24− { "binding": "WEBHOOKS", "service": "g1t-webhooks" },
25− { "binding": "ACTIONS", "service": "g1t-actions" },
26− // Builds of deployments report through here.
27− { "binding": "DEPLOYMENTS", "service": "g1t-deployments" },
28− // Observability: a project's requests, logs, traces, errors and
29− // metrics, and OTLP sent to /otlp/v1/{traces,logs,metrics}.
30− { "binding": "TELEMETRY", "service": "g1t-telemetry" },
31− { "binding": "SEARCH", "service": "g1t-search" },
32− // Secret and dependency alerts: list_security_alerts and dismissing them.
33− { "binding": "SECURITY", "service": "g1t-security" },
34− // A person's pinned projects: list_pinned_projects and changing them.
35− { "binding": "PROJECTS", "service": "g1t-projects" },
36− // Packages: list_packages, their settings, deleting and restoring them.
37− { "binding": "PACKAGES", "service": "g1t-packages" },
38− // Artifacts (folios): the artifact tool and /workspaces/{ws}/artifacts.
39− { "binding": "ARTIFACTS", "service": "g1t-artifacts" }
40− ],
41− // GitHub Actions artifacts older runners kept, in chunks, with KV's own
42− // expiry, read until it passes (and cache
43− // entries saved before the cache moved to R2, until they expire).
44− "kv_namespaces": [{ "binding": "BLOBS", "id": "16a4232cb746418db53782aa068be693" }],
45− // actions/cache entries (`c/`) and artifacts (`a/`), uploaded in parts. The actions
46− // service lists them and decides what is kept (services/actions/src/cache.rs).
47− "r2_buckets": [{ "binding": "ACTIONS_CACHE", "bucket_name": "g1t-actions-cache" }],
48− // REST and MCP requests (src/limits.rs): per token, or per address
49− // without one. Ids and limits: RATE_LIMITS in packages/contracts.
50− "ratelimits": [
51− { "name": "API_ANONYMOUS_LIMIT", "namespace_id": "4401", "simple": { "limit": 60, "period": 60 } },
52− { "name": "API_TOKEN_LIMIT", "namespace_id": "4402", "simple": { "limit": 1000, "period": 60 } }
53− ],
54− // Logs of a tenth of requests: agents call it constantly.
55− "observability": { "enabled": true, "head_sampling_rate": 0.1 }
2+ "$schema": "../../node_modules/wrangler/config-schema.json",
3+ "name": "g1t-api",
4+ "account_id": "1e6f2cffa3f445920836e8ebe446bb58",
5+ "compatibility_date": "2026-09-26",
6+ "placement": { "mode": "off" },
7+ "main": "build/index.js",
8+ "build": { "command": "node ../../scripts/build-rust-worker.mjs" },
9+ "workers_dev": false,
10+ // One Worker, two hostnames: REST on api, MCP on mcp. Both are thin
11+ // adapters over the same operations.
12+ "routes": [
13+ { "pattern": "api.g1t.sh", "custom_domain": true },
14+ { "pattern": "mcp.g1t.sh", "custom_domain": true },
15+ ],
16+ "services": [
17+ { "binding": "IDENTITY", "service": "g1t-identity" },
18+ { "binding": "REPOS", "service": "g1t-repos" },
19+ { "binding": "WORK", "service": "g1t-work" },
20+ { "binding": "EVENTS", "service": "g1t-events" },
21+ { "binding": "RUNNER", "service": "g1t-runner" },
22+ { "binding": "BILLING", "service": "g1t-billing" },
23+ { "binding": "INTEGRATIONS", "service": "g1t-integrations" },
24+ { "binding": "WEBHOOKS", "service": "g1t-webhooks" },
25+ { "binding": "ACTIONS", "service": "g1t-actions" },
26+ // Builds of deployments report through here.
27+ { "binding": "DEPLOYMENTS", "service": "g1t-deployments" },
28+ // Observability: a project's requests, logs, traces, errors and
29+ // metrics, and OTLP sent to /otlp/v1/{traces,logs,metrics}.
30+ { "binding": "TELEMETRY", "service": "g1t-telemetry" },
31+ { "binding": "SEARCH", "service": "g1t-search" },
32+ // Secret and dependency alerts: list_security_alerts and dismissing them.
33+ { "binding": "SECURITY", "service": "g1t-security" },
34+ // A person's pinned projects: list_pinned_projects and changing them.
35+ { "binding": "PROJECTS", "service": "g1t-projects" },
36+ // Packages: list_packages, their settings, deleting and restoring them.
37+ { "binding": "PACKAGES", "service": "g1t-packages" },
38+ // Artifacts (folios): the artifact tool and /workspaces/{ws}/artifacts.
39+ { "binding": "ARTIFACTS", "service": "g1t-artifacts" },
40+ ],
41+ // GitHub Actions artifacts older runners kept, in chunks, with KV's own
42+ // expiry, read until it passes (and cache
43+ // entries saved before the cache moved to R2, until they expire).
44+ "kv_namespaces": [{ "binding": "BLOBS", "id": "16a4232cb746418db53782aa068be693" }],
45+ // actions/cache entries (`c/`) and artifacts (`a/`), uploaded in parts. The actions
46+ // service lists them and decides what is kept (services/actions/src/cache.rs).
47+ "r2_buckets": [{ "binding": "ACTIONS_CACHE", "bucket_name": "g1t-actions-cache" }],
48+ // REST and MCP requests (src/limits.rs): per token, or per address
49+ // without one. Ids and limits: RATE_LIMITS in packages/contracts.
50+ "ratelimits": [
51+ { "name": "API_ANONYMOUS_LIMIT", "namespace_id": "4401", "simple": { "limit": 60, "period": 60 } },
52+ { "name": "API_TOKEN_LIMIT", "namespace_id": "4402", "simple": { "limit": 1000, "period": 60 } },
53+ ],
54+ // Logs of a tenth of requests: agents call it constantly.
55+ "observability": { "enabled": true, "head_sampling_rate": 0.1 },
5656 }
+54−54
66 what you see. It is also where another g1t is chosen (?change).
77 -->
88 <html lang="en">
9− <head>
10− <meta charset="utf-8" />
11− <meta name="viewport" content="width=device-width, initial-scale=1" />
12− <meta name="color-scheme" content="dark" />
13− <title>g1t</title>
14− <link rel="stylesheet" href="launcher.css" />
15− </head>
16− <body>
17− <main>
18− <svg class="mark" viewBox="0 0 256 256" shape-rendering="crispEdges" aria-hidden="true">
19− <rect width="256" height="256" rx="56" shape-rendering="geometricPrecision" fill="#0f0f11" />
20− <rect x="118" y="43" width="20" height="20" fill="#b6a8ff" />
21− <rect x="93" y="68" width="20" height="20" fill="#b6a8ff" />
22− <rect x="118" y="68" width="20" height="20" fill="#b6a8ff" />
23− <rect x="68" y="93" width="20" height="20" fill="#b6a8ff" />
24− <rect x="118" y="93" width="20" height="20" fill="#b6a8ff" />
25− <rect x="118" y="118" width="20" height="20" fill="#b6a8ff" />
26− <rect x="118" y="143" width="20" height="20" fill="#b6a8ff" />
27− <rect x="118" y="168" width="20" height="20" fill="#b6a8ff" />
28− <rect x="68" y="193" width="20" height="20" fill="#b6a8ff" />
29− <rect x="93" y="193" width="20" height="20" fill="#b6a8ff" />
30− <rect x="118" y="193" width="20" height="20" fill="#b6a8ff" />
31− <rect x="143" y="193" width="20" height="20" fill="#b6a8ff" />
32− <rect x="168" y="193" width="20" height="20" fill="#b6a8ff" />
33− </svg>
9+ <head>
10+ <meta charset="utf-8" />
11+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12+ <meta name="color-scheme" content="dark" />
13+ <title>g1t</title>
14+ <link rel="stylesheet" href="launcher.css" />
15+ </head>
16+ <body>
17+ <main>
18+ <svg class="mark" viewBox="0 0 256 256" shape-rendering="crispEdges" aria-hidden="true">
19+ <rect width="256" height="256" rx="56" shape-rendering="geometricPrecision" fill="#0f0f11" />
20+ <rect x="118" y="43" width="20" height="20" fill="#b6a8ff" />
21+ <rect x="93" y="68" width="20" height="20" fill="#b6a8ff" />
22+ <rect x="118" y="68" width="20" height="20" fill="#b6a8ff" />
23+ <rect x="68" y="93" width="20" height="20" fill="#b6a8ff" />
24+ <rect x="118" y="93" width="20" height="20" fill="#b6a8ff" />
25+ <rect x="118" y="118" width="20" height="20" fill="#b6a8ff" />
26+ <rect x="118" y="143" width="20" height="20" fill="#b6a8ff" />
27+ <rect x="118" y="168" width="20" height="20" fill="#b6a8ff" />
28+ <rect x="68" y="193" width="20" height="20" fill="#b6a8ff" />
29+ <rect x="93" y="193" width="20" height="20" fill="#b6a8ff" />
30+ <rect x="118" y="193" width="20" height="20" fill="#b6a8ff" />
31+ <rect x="143" y="193" width="20" height="20" fill="#b6a8ff" />
32+ <rect x="168" y="193" width="20" height="20" fill="#b6a8ff" />
33+ </svg>
3434
35− <section id="connecting" hidden>
36− <p class="status"><span class="pulse"></span><span id="connecting-text">Connecting to g1t…</span></p>
37− </section>
35+ <section id="connecting" hidden>
36+ <p class="status"><span class="pulse"></span><span id="connecting-text">Connecting to g1t…</span></p>
37+ </section>
3838
39− <section id="offline" hidden>
40− <h1 id="offline-title">Can't reach g1t.sh</h1>
41− <p class="muted">Check your connection, then try again. If g1t.sh itself is down, its status page says so.</p>
42− <div class="row">
43− <button id="retry" type="button" class="primary">Try again</button>
44− <button id="change" type="button">Use another g1t…</button>
45− </div>
46− <p class="muted small"><a id="status-link" href="https://status.g1t.sh/">status.g1t.sh</a></p>
47− </section>
39+ <section id="offline" hidden>
40+ <h1 id="offline-title">Can't reach g1t.sh</h1>
41+ <p class="muted">Check your connection, then try again. If g1t.sh itself is down, its status page says so.</p>
42+ <div class="row">
43+ <button id="retry" type="button" class="primary">Try again</button>
44+ <button id="change" type="button">Use another g1t…</button>
45+ </div>
46+ <p class="muted small"><a id="status-link" href="https://status.g1t.sh/">status.g1t.sh</a></p>
47+ </section>
4848
49− <section id="choose" hidden>
50− <h1>Which g1t?</h1>
51− <p class="muted">g1t.sh unless you run g1t yourself. Enter your g1t's address to use it instead; the app keeps it.</p>
52− <form id="server-form">
53− <label for="server">Address</label>
54− <input id="server" name="server" type="url" inputmode="url" autocomplete="off" spellcheck="false" placeholder="https://g1t.example.com" />
55− <p id="server-error" class="error" hidden></p>
56− <div class="row">
57− <button type="submit" class="primary">Use this g1t</button>
58− <button id="use-default" type="button">Use g1t.sh</button>
59− </div>
60− </form>
61− </section>
49+ <section id="choose" hidden>
50+ <h1>Which g1t?</h1>
51+ <p class="muted">g1t.sh unless you run g1t yourself. Enter your g1t's address to use it instead; the app keeps it.</p>
52+ <form id="server-form">
53+ <label for="server">Address</label>
54+ <input id="server" name="server" type="url" inputmode="url" autocomplete="off" spellcheck="false" placeholder="https://g1t.example.com" />
55+ <p id="server-error" class="error" hidden></p>
56+ <div class="row">
57+ <button type="submit" class="primary">Use this g1t</button>
58+ <button id="use-default" type="button">Use g1t.sh</button>
59+ </div>
60+ </form>
61+ </section>
6262
63− <p class="version muted small" id="version"></p>
64− </main>
65− <script src="launcher.js"></script>
66− </body>
63+ <p class="version muted small" id="version"></p>
64+ </main>
65+ <script src="launcher.js"></script>
66+ </body>
6767 </html>
+105−100
11 /* The launcher, in the site's colours (packages/theme/tokens.css): a very
22 dark gray and lavender, the mark centred, one short message. */
33 :root {
4− --bg: #0f0f11;
5− --fg: #ededf0;
6− --muted: #9a9aa6;
7− --line: #26262c;
8− --surface: #17171b;
9− --accent: #b6a8ff;
10− --accent-ink: #15112e;
11− --error: #ff8a8a;
12− color-scheme: dark;
4+ --bg: #0f0f11;
5+ --fg: #ededf0;
6+ --muted: #9a9aa6;
7+ --line: #26262c;
8+ --surface: #17171b;
9+ --accent: #b6a8ff;
10+ --accent-ink: #15112e;
11+ --error: #ff8a8a;
12+ color-scheme: dark;
1313 }
1414 * {
15− box-sizing: border-box;
15+ box-sizing: border-box;
1616 }
1717 html,
1818 body {
19− height: 100%;
20− margin: 0;
19+ height: 100%;
20+ margin: 0;
2121 }
2222 body {
23− background: var(--bg);
24− color: var(--fg);
25− font: 15px/1.5 system-ui, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
26− -webkit-font-smoothing: antialiased;
27− display: grid;
28− place-items: center;
29− user-select: none;
30− cursor: default;
23+ background: var(--bg);
24+ color: var(--fg);
25+ font:
26+ 15px/1.5 system-ui,
27+ "Segoe UI",
28+ Roboto,
29+ "Helvetica Neue",
30+ sans-serif;
31+ -webkit-font-smoothing: antialiased;
32+ display: grid;
33+ place-items: center;
34+ user-select: none;
35+ cursor: default;
3136 }
3237 main {
33− width: min(26rem, calc(100vw - 2rem));
34− text-align: center;
38+ width: min(26rem, calc(100vw - 2rem));
39+ text-align: center;
3540 }
3641 .mark {
37− width: 72px;
38− height: 72px;
39− display: block;
40− margin: 0 auto 1.5rem;
41− border-radius: 16px;
42− box-shadow: 0 0 0 1px var(--line);
42+ width: 72px;
43+ height: 72px;
44+ display: block;
45+ margin: 0 auto 1.5rem;
46+ border-radius: 16px;
47+ box-shadow: 0 0 0 1px var(--line);
4348 }
4449 h1 {
45− font-size: 1.125rem;
46− font-weight: 600;
47− margin: 0 0 0.5rem;
50+ font-size: 1.125rem;
51+ font-weight: 600;
52+ margin: 0 0 0.5rem;
4853 }
4954 p {
50− margin: 0 0 1rem;
55+ margin: 0 0 1rem;
5156 }
5257 .muted {
53− color: var(--muted);
58+ color: var(--muted);
5459 }
5560 .small {
56− font-size: 0.8125rem;
61+ font-size: 0.8125rem;
5762 }
5863 .error {
59− color: var(--error);
60− font-size: 0.875rem;
61− text-align: left;
64+ color: var(--error);
65+ font-size: 0.875rem;
66+ text-align: left;
6267 }
6368 .status {
64− display: inline-flex;
65− align-items: center;
66− gap: 0.625rem;
67− color: var(--muted);
69+ display: inline-flex;
70+ align-items: center;
71+ gap: 0.625rem;
72+ color: var(--muted);
6873 }
6974 .pulse {
70− width: 8px;
71− height: 8px;
72− border-radius: 50%;
73− background: var(--accent);
74− animation: pulse 1.4s ease-in-out infinite;
75+ width: 8px;
76+ height: 8px;
77+ border-radius: 50%;
78+ background: var(--accent);
79+ animation: pulse 1.4s ease-in-out infinite;
7580 }
7681 @keyframes pulse {
77− 0%,
78− 100% {
79− opacity: 0.35;
80− transform: scale(0.85);
81− }
82− 50% {
83− opacity: 1;
84− transform: scale(1);
85− }
82+ 0%,
83+ 100% {
84+ opacity: 0.35;
85+ transform: scale(0.85);
86+ }
87+ 50% {
88+ opacity: 1;
89+ transform: scale(1);
90+ }
8691 }
8792 @media (prefers-reduced-motion: reduce) {
88− .pulse {
89− animation: none;
90− }
93+ .pulse {
94+ animation: none;
95+ }
9196 }
9297 .row {
93− display: flex;
94− gap: 0.5rem;
95− justify-content: center;
96− flex-wrap: wrap;
97− margin-bottom: 1rem;
98+ display: flex;
99+ gap: 0.5rem;
100+ justify-content: center;
101+ flex-wrap: wrap;
102+ margin-bottom: 1rem;
98103 }
99104 button {
100− font: inherit;
101− font-size: 0.875rem;
102− font-weight: 500;
103− padding: 0.5rem 0.875rem;
104− border-radius: 8px;
105− border: 1px solid var(--line);
106− background: var(--surface);
107− color: var(--fg);
108− cursor: default;
105+ font: inherit;
106+ font-size: 0.875rem;
107+ font-weight: 500;
108+ padding: 0.5rem 0.875rem;
109+ border-radius: 8px;
110+ border: 1px solid var(--line);
111+ background: var(--surface);
112+ color: var(--fg);
113+ cursor: default;
109114 }
110115 button:hover {
111− border-color: #3a3a44;
116+ border-color: #3a3a44;
112117 }
113118 button:focus-visible,
114119 input:focus-visible {
115− outline: 2px solid var(--accent);
116− outline-offset: 2px;
120+ outline: 2px solid var(--accent);
121+ outline-offset: 2px;
117122 }
118123 button.primary {
119− background: var(--accent);
120− border-color: var(--accent);
121− color: var(--accent-ink);
124+ background: var(--accent);
125+ border-color: var(--accent);
126+ color: var(--accent-ink);
122127 }
123128 button.primary:hover {
124− filter: brightness(1.06);
129+ filter: brightness(1.06);
125130 }
126131 form {
127− text-align: left;
132+ text-align: left;
128133 }
129134 label {
130− display: block;
131− font-size: 0.8125rem;
132− color: var(--muted);
133− margin-bottom: 0.25rem;
135+ display: block;
136+ font-size: 0.8125rem;
137+ color: var(--muted);
138+ margin-bottom: 0.25rem;
134139 }
135140 input {
136− font: inherit;
137− width: 100%;
138− padding: 0.5rem 0.625rem;
139− border-radius: 8px;
140− border: 1px solid var(--line);
141− background: var(--surface);
142− color: var(--fg);
143− margin-bottom: 0.75rem;
144− user-select: text;
141+ font: inherit;
142+ width: 100%;
143+ padding: 0.5rem 0.625rem;
144+ border-radius: 8px;
145+ border: 1px solid var(--line);
146+ background: var(--surface);
147+ color: var(--fg);
148+ margin-bottom: 0.75rem;
149+ user-select: text;
145150 }
146151 a {
147− color: var(--muted);
148− text-decoration: underline;
149− text-underline-offset: 3px;
152+ color: var(--muted);
153+ text-decoration: underline;
154+ text-underline-offset: 3px;
150155 }
151156 a:hover {
152− color: var(--fg);
157+ color: var(--fg);
153158 }
154159 .version {
155− margin-top: 2.5rem;
156− margin-bottom: 0;
157− font-variant-numeric: tabular-nums;
160+ margin-top: 2.5rem;
161+ margin-bottom: 0;
162+ font-variant-numeric: tabular-nums;
158163 }
+88−87
1010 (src/runner/diagnosis.rs).
1111 -->
1212 <html lang="en">
13− <head>
14− <meta charset="utf-8" />
15− <meta name="viewport" content="width=device-width, initial-scale=1" />
16− <meta name="color-scheme" content="dark" />
17− <title>g1t runner</title>
18− <link rel="stylesheet" href="settings.css" />
19− </head>
20− <body>
21− <!-- Its title bar, when g1t draws its own (src/frame.rs): drag it to move the window. -->
22− <header class="titlebar" id="titlebar" hidden>
23− <span>Runner</span>
24− <button type="button" id="close-window" class="caption" aria-label="Close" title="Close" tabindex="-1">
25− <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" aria-hidden="true">
26− <line x1="4" y1="4" x2="12" y2="12" />
27− <line x1="12" y1="4" x2="4" y2="12" />
28− </svg>
29− </button>
30− </header>
31− <div class="page">
32− <main>
33− <h1>Runner</h1>
34− <p class="muted lede">Your workspace's <code>runs-on: self-hosted</code> jobs run on this computer while g1t is open, at no cost.</p>
13+ <head>
14+ <meta charset="utf-8" />
15+ <meta name="viewport" content="width=device-width, initial-scale=1" />
16+ <meta name="color-scheme" content="dark" />
17+ <title>g1t runner</title>
18+ <link rel="stylesheet" href="settings.css" />
19+ </head>
20+ <body>
21+ <!-- Its title bar, when g1t draws its own (src/frame.rs): drag it to move the window. -->
22+ <header class="titlebar" id="titlebar" hidden>
23+ <span>Runner</span>
24+ <button type="button" id="close-window" class="caption" aria-label="Close" title="Close" tabindex="-1">
25+ <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" aria-hidden="true">
26+ <line x1="4" y1="4" x2="12" y2="12" />
27+ <line x1="12" y1="4" x2="4" y2="12" />
28+ </svg>
29+ </button>
30+ </header>
31+ <div class="page">
32+ <main>
33+ <h1>Runner</h1>
34+ <p class="muted lede">Your workspace's <code>runs-on: self-hosted</code> jobs run on this computer while g1t is open, at no cost.</p>
3535
36− <!-- What the whole runner is doing, as the title bar's chip says it, with its Start or Stop. -->
37− <div class="engine" id="engine">
38− <span class="dot" id="engine-dot" aria-hidden="true"></span>
39− <span class="engine-text">
40− <strong id="engine-label" role="status" aria-live="polite">Runner</strong>
41− <span class="muted" id="engine-sub">&nbsp;</span>
42− </span>
43− <button type="button" id="engine-toggle" hidden>Stop</button>
44− </div>
36+ <!-- What the whole runner is doing, as the title bar's chip says it, with its Start or Stop. -->
37+ <div class="engine" id="engine">
38+ <span class="dot" id="engine-dot" aria-hidden="true"></span>
39+ <span class="engine-text">
40+ <strong id="engine-label" role="status" aria-live="polite">Runner</strong>
41+ <span class="muted" id="engine-sub">&nbsp;</span>
42+ </span>
43+ <button type="button" id="engine-toggle" hidden>Stop</button>
44+ </div>
4545
46− <section aria-labelledby="kinds-heading" id="runner-section">
47− <h2 id="kinds-heading" class="visually-hidden">Jobs</h2>
48− <!--
46+ <section aria-labelledby="kinds-heading" id="runner-section">
47+ <h2 id="kinds-heading" class="visually-hidden">Jobs</h2>
48+ <!--
4949 What affects the whole runner (signed out, no workspace, turned off,
5050 the sandbox down): why, and how to fix it (src/runner/diagnosis.rs).
5151 Hidden when the cards below say it all.
5252 -->
53− <div class="diagnosis" id="runner-diagnosis" role="status" aria-live="polite" hidden>
54− <span class="dot" id="runner-dot" aria-hidden="true"></span>
55− <span class="diagnosis-text">
56− <strong id="runner-title">Runner</strong>
57− <span class="muted" id="runner-cause"></span>
58− <span id="runner-fix"></span>
59− <span class="buttons" id="runner-actions"></span>
60− </span>
61− </div>
62− <!-- Sandboxed: each kind of job it runs, a card of its own, started and stopped on its own. -->
63− <div class="kinds" id="runner-kinds" role="list" aria-label="Kinds of job this computer runs" hidden></div>
64− </section>
53+ <div class="diagnosis" id="runner-diagnosis" role="status" aria-live="polite" hidden>
54+ <span class="dot" id="runner-dot" aria-hidden="true"></span>
55+ <span class="diagnosis-text">
56+ <strong id="runner-title">Runner</strong>
57+ <span class="muted" id="runner-cause"></span>
58+ <span id="runner-fix"></span>
59+ <span class="buttons" id="runner-actions"></span>
60+ </span>
61+ </div>
62+ <!-- Sandboxed: each kind of job it runs, a card of its own, started and stopped on its own. -->
63+ <div class="kinds" id="runner-kinds" role="list" aria-label="Kinds of job this computer runs" hidden></div>
64+ </section>
6565
66− <section aria-labelledby="setup-heading">
67− <h2 id="setup-heading">Setup</h2>
68− <label class="setting">
69− <span
70− ><strong>Run jobs on this computer while g1t is open</strong
71− ><span class="muted">Off, nothing runs here until you turn it on again.</span></span
72− >
73− <input type="checkbox" role="switch" id="runner" />
74− </label>
75− <label class="setting">
76− <span><strong>How jobs run</strong><span class="muted" id="runner-backend-note">&nbsp;</span></span>
77− <select id="runnerBackend">
78− <option value="sandboxed">Sandboxed (recommended)</option>
79− <option value="docker">In Docker</option>
80− <option value="host">Directly on this computer</option>
81− </select>
82− </label>
83− <label class="setting">
84− <span><strong>Workspace</strong><span class="muted" id="runner-workspace-note">The workspace whose jobs it runs. Only a workspace's owners can add runners to it.</span></span>
85− <select id="runnerWorkspace"></select>
86− </label>
87− <div class="setting">
88− <span><strong id="runner-machine">This computer</strong><span class="muted" id="runner-version">&nbsp;</span></span>
89− <span class="buttons"
90− ><button type="button" id="runner-check" hidden>Check for runner updates</button
91− ><button type="button" id="runner-view">View on g1t</button></span
92− >
93− </div>
94− </section>
66+ <section aria-labelledby="setup-heading">
67+ <h2 id="setup-heading">Setup</h2>
68+ <label class="setting">
69+ <span
70+ ><strong>Run jobs on this computer while g1t is open</strong><span class="muted">Off, nothing runs here until you turn it on again.</span></span
71+ >
72+ <input type="checkbox" role="switch" id="runner" />
73+ </label>
74+ <label class="setting">
75+ <span><strong>How jobs run</strong><span class="muted" id="runner-backend-note">&nbsp;</span></span>
76+ <select id="runnerBackend">
77+ <option value="sandboxed">Sandboxed (recommended)</option>
78+ <option value="docker">In Docker</option>
79+ <option value="host">Directly on this computer</option>
80+ </select>
81+ </label>
82+ <label class="setting">
83+ <span
84+ ><strong>Workspace</strong
85+ ><span class="muted" id="runner-workspace-note">The workspace whose jobs it runs. Only a workspace's owners can add runners to it.</span></span
86+ >
87+ <select id="runnerWorkspace"></select>
88+ </label>
89+ <div class="setting">
90+ <span><strong id="runner-machine">This computer</strong><span class="muted" id="runner-version">&nbsp;</span></span>
91+ <span class="buttons"
92+ ><button type="button" id="runner-check" hidden>Check for runner updates</button><button type="button" id="runner-view">View on g1t</button></span
93+ >
94+ </div>
95+ </section>
9596
96− <section aria-labelledby="log-heading">
97− <h2 id="log-heading">Log</h2>
98− <pre class="live-log" id="runner-log" tabindex="0" aria-label="The runner's recent log">Nothing yet.</pre>
99− <p class="buttons"><button type="button" id="runner-open-log">Open the whole log</button></p>
100− </section>
97+ <section aria-labelledby="log-heading">
98+ <h2 id="log-heading">Log</h2>
99+ <pre class="live-log" id="runner-log" tabindex="0" aria-label="The runner's recent log">Nothing yet.</pre>
100+ <p class="buttons"><button type="button" id="runner-open-log">Open the whole log</button></p>
101+ </section>
101102
102− <p class="error" id="error" role="alert" hidden></p>
103− <p class="muted small foot"><a href="https://docs.g1t.sh/guides/desktop/#the-runner">About the runner</a></p>
104− </main>
105− </div>
106− <script src="busy.js"></script>
107− <script src="runner.js"></script>
108− </body>
103+ <p class="error" id="error" role="alert" hidden></p>
104+ <p class="muted small foot"><a href="https://docs.g1t.sh/guides/desktop/#the-runner">About the runner</a></p>
105+ </main>
106+ </div>
107+ <script src="busy.js"></script>
108+ <script src="runner.js"></script>
109+ </body>
109110 </html>
+76−21
5151 function runnerStatus(runner) {
5252 var d = runner.diagnosis;
5353 var update = d.update || {};
54− return JSON.stringify([d.code, d.tone, d.title, d.cause, runner.chip.label, runner.enabled, runner.paused, update.checking, update.checked_at, update.ready]);
54+ return JSON.stringify([
55+ d.code,
56+ d.tone,
57+ d.title,
58+ d.cause,
59+ runner.chip.label,
60+ runner.enabled,
61+ runner.paused,
62+ update.checking,
63+ update.checked_at,
64+ update.ready,
65+ ]);
5566 }
5667
5768 // One kind of job's, with the whole runner's.
7485 if (action.id === "choose_workspace") return byId("runnerWorkspace").focus();
7586 if (action.id === "choose_backend") return byId("runnerBackend").focus();
7687 if (action.confirm && !window.confirm(action.confirm)) return;
77− busy.run(button, key, status, !!action.waits, function () {
78− return invoke("runner_control", { action: action.id });
79− }, fail).then(function (done) {
80− if (!done || action.id.indexOf("copy_") !== 0) return;
81− button.textContent = "Copied";
82− setTimeout(function () {
83− button.textContent = action.label;
84− }, 2000);
85− });
88+ busy
89+ .run(
90+ button,
91+ key,
92+ status,
93+ !!action.waits,
94+ function () {
95+ return invoke("runner_control", { action: action.id });
96+ },
97+ fail,
98+ )
99+ .then(function (done) {
100+ if (!done || action.id.indexOf("copy_") !== 0) return;
101+ button.textContent = "Copied";
102+ setTimeout(function () {
103+ button.textContent = action.label;
104+ }, 2000);
105+ });
86106 });
87107 return button;
88108 }
251271 var status = kindStatus(kind, runner);
252272 if (busy.pressed(key, status)) busy.start(button);
253273 button.addEventListener("click", function () {
254− busy.run(button, key, status, true, function () {
255− return invoke("runner_control", { action: on ? "stop" : "start", capability: kind.id });
256− }, fail);
274+ busy.run(
275+ button,
276+ key,
277+ status,
278+ true,
279+ function () {
280+ return invoke("runner_control", { action: on ? "stop" : "start", capability: kind.id });
281+ },
282+ fail,
283+ );
257284 });
258285 return button;
259286 }
417444 var button = byId(id);
418445 button.addEventListener("click", function () {
419446 var status = current && current.runnerView ? runnerStatus(current.runnerView) : "";
420− busy.run(button, key, status, waits, function () {
421− return invoke("runner_control", { action: typeof action === "function" ? action() : action });
422− }, fail);
447+ busy.run(
448+ button,
449+ key,
450+ status,
451+ waits,
452+ function () {
453+ return invoke("runner_control", { action: typeof action === "function" ? action() : action });
454+ },
455+ fail,
456+ );
423457 });
424458 }
425459 control("runner-view", "view", "view_runners", false);
434468 byId("engine-dot").className = "dot " + runner.chip.tone;
435469 var label = byId("engine-label");
436470 if (label.textContent !== runner.chip.label) label.textContent = runner.chip.label;
437− var about = [runner.diagnosis.title, runner.version ? "g1t-runner " + runner.version : null, runner.workspace ? "for " + runner.workspace : null].filter(Boolean);
471+ var about = [runner.diagnosis.title, runner.version ? "g1t-runner " + runner.version : null, runner.workspace ? "for " + runner.workspace : null].filter(
472+ Boolean,
473+ );
438474 byId("engine-sub").textContent = about.join(" · ");
439475 var toggle = byId("engine-toggle");
440476 var on = runner.enabled && !runner.paused;
444480 toggle.dataset.action = on ? "stop" : "start";
445481 }
446482
447− control("engine-toggle", "engine", function () {
448− return byId("engine-toggle").dataset.action;
449− }, true);
483+ control(
484+ "engine-toggle",
485+ "engine",
486+ function () {
487+ return byId("engine-toggle").dataset.action;
488+ },
489+ true,
490+ );
450491
451492 // Every setting, as the app has it now (the settings window changes the
452493 // rest), with the runner's own as they are on the page.
453− var KEPT = ["startHidden", "closeToTray", "notifications", "flash", "badge", "systemTitleBar", "autoUpdate", "zoom", "developerTools", "runner", "runnerBackend", "runnerWorkspace", "runnerCapabilities"];
494+ var KEPT = [
495+ "startHidden",
496+ "closeToTray",
497+ "notifications",
498+ "flash",
499+ "badge",
500+ "systemTitleBar",
501+ "autoUpdate",
502+ "zoom",
503+ "developerTools",
504+ "runner",
505+ "runnerBackend",
506+ "runnerWorkspace",
507+ "runnerCapabilities",
508+ ];
454509 function save() {
455510 invoke("get_settings")
456511 .then(function (fresh) {
+463−446
A large diff (1,202 lines) is not shown until you ask for it.
+136−120
55 change is kept as soon as it is made; there is nothing to save.
66 -->
77 <html lang="en">
8− <head>
9− <meta charset="utf-8" />
10− <meta name="viewport" content="width=device-width, initial-scale=1" />
11− <meta name="color-scheme" content="dark" />
12− <title>g1t settings</title>
13− <link rel="stylesheet" href="settings.css" />
14− </head>
15− <body>
16− <!-- Its title bar, when g1t draws its own (src/frame.rs): drag it to move the window. -->
17− <header class="titlebar" id="titlebar" hidden>
18− <span>Settings</span>
19− <button type="button" id="close-window" class="caption" aria-label="Close" title="Close" tabindex="-1">
20− <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" aria-hidden="true">
21− <line x1="4" y1="4" x2="12" y2="12" />
22− <line x1="12" y1="4" x2="4" y2="12" />
23− </svg>
24− </button>
25− </header>
26− <div class="page">
27− <main>
28− <h1>Settings</h1>
29− <p class="muted lede">For the desktop app on this computer. Your account's settings, notifications included, are on g1t itself.</p>
8+ <head>
9+ <meta charset="utf-8" />
10+ <meta name="viewport" content="width=device-width, initial-scale=1" />
11+ <meta name="color-scheme" content="dark" />
12+ <title>g1t settings</title>
13+ <link rel="stylesheet" href="settings.css" />
14+ </head>
15+ <body>
16+ <!-- Its title bar, when g1t draws its own (src/frame.rs): drag it to move the window. -->
17+ <header class="titlebar" id="titlebar" hidden>
18+ <span>Settings</span>
19+ <button type="button" id="close-window" class="caption" aria-label="Close" title="Close" tabindex="-1">
20+ <svg viewBox="0 0 16 16" width="16" height="16" fill="none" stroke="currentColor" stroke-width="1.25" stroke-linecap="round" aria-hidden="true">
21+ <line x1="4" y1="4" x2="12" y2="12" />
22+ <line x1="12" y1="4" x2="4" y2="12" />
23+ </svg>
24+ </button>
25+ </header>
26+ <div class="page">
27+ <main>
28+ <h1>Settings</h1>
29+ <p class="muted lede">For the desktop app on this computer. Your account's settings, notifications included, are on g1t itself.</p>
3030
31− <section aria-labelledby="general-heading">
32− <h2 id="general-heading">Starting and closing</h2>
33− <label class="setting">
34− <span><strong>Open g1t when you sign in</strong><span class="muted" id="open-at-login-note">g1t starts with your computer.</span></span>
35− <input type="checkbox" role="switch" id="openAtLogin" />
36− </label>
37− <label class="setting">
38− <span><strong>Start in the tray</strong><span class="muted" id="start-hidden-note">Opened at sign-in, g1t waits in the tray without opening its window.</span></span>
39− <input type="checkbox" role="switch" id="startHidden" />
40− </label>
41− <label class="setting">
42− <span><strong>Keep g1t running when the window closes</strong><span class="muted">It stays in the tray for notifications. Turned off, closing the window quits.</span></span>
43− <input type="checkbox" role="switch" id="closeToTray" />
44− </label>
45− </section>
31+ <section aria-labelledby="general-heading">
32+ <h2 id="general-heading">Starting and closing</h2>
33+ <label class="setting">
34+ <span><strong>Open g1t when you sign in</strong><span class="muted" id="open-at-login-note">g1t starts with your computer.</span></span>
35+ <input type="checkbox" role="switch" id="openAtLogin" />
36+ </label>
37+ <label class="setting">
38+ <span
39+ ><strong>Start in the tray</strong
40+ ><span class="muted" id="start-hidden-note">Opened at sign-in, g1t waits in the tray without opening its window.</span></span
41+ >
42+ <input type="checkbox" role="switch" id="startHidden" />
43+ </label>
44+ <label class="setting">
45+ <span
46+ ><strong>Keep g1t running when the window closes</strong
47+ ><span class="muted">It stays in the tray for notifications. Turned off, closing the window quits.</span></span
48+ >
49+ <input type="checkbox" role="switch" id="closeToTray" />
50+ </label>
51+ </section>
4652
47− <section aria-labelledby="runner-heading" id="runner-section">
48− <h2 id="runner-heading">Runner</h2>
49− <!-- What it is doing, in a line; the Runner window has the rest (runner.html). -->
50− <div class="setting">
51− <span
52− ><strong class="runner-line"><span class="dot" id="runner-dot" aria-hidden="true"></span><span id="runner-title" role="status" aria-live="polite">Runner</span></strong
53− ><span class="muted" id="runner-summary">Your workspace's <code>runs-on: self-hosted</code> jobs, on this computer while g1t is open.</span></span
54− >
55− <span class="buttons"><button type="button" id="open-runner">Open runner</button></span>
56− </div>
57− </section>
53+ <section aria-labelledby="runner-heading" id="runner-section">
54+ <h2 id="runner-heading">Runner</h2>
55+ <!-- What it is doing, in a line; the Runner window has the rest (runner.html). -->
56+ <div class="setting">
57+ <span
58+ ><strong class="runner-line"
59+ ><span class="dot" id="runner-dot" aria-hidden="true"></span><span id="runner-title" role="status" aria-live="polite">Runner</span></strong
60+ ><span class="muted" id="runner-summary">Your workspace's <code>runs-on: self-hosted</code> jobs, on this computer while g1t is open.</span></span
61+ >
62+ <span class="buttons"><button type="button" id="open-runner">Open runner</button></span>
63+ </div>
64+ </section>
5865
59− <section aria-labelledby="notifications-heading">
60− <h2 id="notifications-heading">Notifications</h2>
61− <label class="setting">
62− <span><strong>Show notifications</strong><span class="muted">From your system, for what needs you while g1t is behind another window. Which things notify you is set on g1t.</span></span>
63− <input type="checkbox" role="switch" id="notifications" />
64− </label>
65− <label class="setting">
66− <span><strong id="flash-label">Flash the taskbar icon</strong><span class="muted">When a notification arrives and the window is not in front.</span></span>
67− <input type="checkbox" role="switch" id="flash" />
68− </label>
69− <label class="setting">
70− <span><strong>Show a badge on the icon</strong><span class="muted">How many things are waiting for you.</span></span>
71− <input type="checkbox" role="switch" id="badge" />
72− </label>
73− </section>
66+ <section aria-labelledby="notifications-heading">
67+ <h2 id="notifications-heading">Notifications</h2>
68+ <label class="setting">
69+ <span
70+ ><strong>Show notifications</strong
71+ ><span class="muted">From your system, for what needs you while g1t is behind another window. Which things notify you is set on g1t.</span></span
72+ >
73+ <input type="checkbox" role="switch" id="notifications" />
74+ </label>
75+ <label class="setting">
76+ <span
77+ ><strong id="flash-label">Flash the taskbar icon</strong
78+ ><span class="muted">When a notification arrives and the window is not in front.</span></span
79+ >
80+ <input type="checkbox" role="switch" id="flash" />
81+ </label>
82+ <label class="setting">
83+ <span><strong>Show a badge on the icon</strong><span class="muted">How many things are waiting for you.</span></span>
84+ <input type="checkbox" role="switch" id="badge" />
85+ </label>
86+ </section>
7487
75− <section aria-labelledby="window-heading">
76− <h2 id="window-heading">Window</h2>
77− <label class="setting">
78− <span
79− ><strong>Use the system's title bar</strong
80− ><span class="muted" id="system-title-bar-note">In place of g1t's own, with the menu bar under it.</span></span
81− >
82− <input type="checkbox" role="switch" id="systemTitleBar" />
83− </label>
84− <div class="setting" id="restart-row" hidden>
85− <span><strong>Restart to change the title bar</strong><span class="muted">g1t opens again where you were.</span></span>
86− <button type="button" id="restart-app" class="primary">Restart now</button>
87− </div>
88− <label class="setting">
89− <span><strong>Zoom</strong><span class="muted" id="zoom-note">The View menu changes it too.</span></span>
90− <select id="zoom">
91− <option value="0.67">67%</option>
92− <option value="0.75">75%</option>
93− <option value="0.8">80%</option>
94− <option value="0.9">90%</option>
95− <option value="1">100%</option>
96− <option value="1.1">110%</option>
97− <option value="1.25">125%</option>
98− <option value="1.5">150%</option>
99− <option value="1.75">175%</option>
100− <option value="2">200%</option>
101− </select>
102− </label>
103− </section>
88+ <section aria-labelledby="window-heading">
89+ <h2 id="window-heading">Window</h2>
90+ <label class="setting">
91+ <span
92+ ><strong>Use the system's title bar</strong
93+ ><span class="muted" id="system-title-bar-note">In place of g1t's own, with the menu bar under it.</span></span
94+ >
95+ <input type="checkbox" role="switch" id="systemTitleBar" />
96+ </label>
97+ <div class="setting" id="restart-row" hidden>
98+ <span><strong>Restart to change the title bar</strong><span class="muted">g1t opens again where you were.</span></span>
99+ <button type="button" id="restart-app" class="primary">Restart now</button>
100+ </div>
101+ <label class="setting">
102+ <span><strong>Zoom</strong><span class="muted" id="zoom-note">The View menu changes it too.</span></span>
103+ <select id="zoom">
104+ <option value="0.67">67%</option>
105+ <option value="0.75">75%</option>
106+ <option value="0.8">80%</option>
107+ <option value="0.9">90%</option>
108+ <option value="1">100%</option>
109+ <option value="1.1">110%</option>
110+ <option value="1.25">125%</option>
111+ <option value="1.5">150%</option>
112+ <option value="1.75">175%</option>
113+ <option value="2">200%</option>
114+ </select>
115+ </label>
116+ </section>
104117
105− <section aria-labelledby="updates-heading">
106− <h2 id="updates-heading">Updates</h2>
107− <label class="setting">
108− <span><strong>Download updates by themselves</strong><span class="muted">Each one installs when you restart or quit g1t, never in the middle of something.</span></span>
109− <input type="checkbox" role="switch" id="autoUpdate" />
110− </label>
111− <div class="setting" id="updates-row">
112− <span><strong id="version">g1t</strong><span class="muted" id="update-status" aria-live="polite">&nbsp;</span></span>
113− <span class="buttons">
114− <button type="button" id="restart" class="primary" hidden>Restart now</button>
115− <button type="button" id="check">Check for updates</button>
116− </span>
117− </div>
118− </section>
118+ <section aria-labelledby="updates-heading">
119+ <h2 id="updates-heading">Updates</h2>
120+ <label class="setting">
121+ <span
122+ ><strong>Download updates by themselves</strong
123+ ><span class="muted">Each one installs when you restart or quit g1t, never in the middle of something.</span></span
124+ >
125+ <input type="checkbox" role="switch" id="autoUpdate" />
126+ </label>
127+ <div class="setting" id="updates-row">
128+ <span><strong id="version">g1t</strong><span class="muted" id="update-status" aria-live="polite">&nbsp;</span></span>
129+ <span class="buttons">
130+ <button type="button" id="restart" class="primary" hidden>Restart now</button>
131+ <button type="button" id="check">Check for updates</button>
132+ </span>
133+ </div>
134+ </section>
119135
120− <section aria-labelledby="server-heading">
121− <h2 id="server-heading">Server</h2>
122− <div class="setting">
123− <span><strong id="server">g1t.sh</strong><span class="muted">The g1t this app opens. Change it if you run g1t yourself.</span></span>
124− <button type="button" id="change-server">Change…</button>
125− </div>
126− </section>
136+ <section aria-labelledby="server-heading">
137+ <h2 id="server-heading">Server</h2>
138+ <div class="setting">
139+ <span><strong id="server">g1t.sh</strong><span class="muted">The g1t this app opens. Change it if you run g1t yourself.</span></span>
140+ <button type="button" id="change-server">Change…</button>
141+ </div>
142+ </section>
127143
128− <p class="error" id="error" role="alert" hidden></p>
129− <p class="muted small foot"><a href="https://docs.g1t.sh/guides/desktop/">About the desktop app</a></p>
130− </main>
131− </div>
132− <script src="busy.js"></script>
133− <script src="settings.js"></script>
134− </body>
144+ <p class="error" id="error" role="alert" hidden></p>
145+ <p class="muted small foot"><a href="https://docs.g1t.sh/guides/desktop/">About the desktop app</a></p>
146+ </main>
147+ </div>
148+ <script src="busy.js"></script>
149+ <script src="settings.js"></script>
150+ </body>
135151 </html>
+25−12
3737
3838 // What changes between Windows, macOS and Linux.
3939 function platform(name) {
40− byId("flash-label").textContent =
41− name === "macos" ? "Bounce the dock icon" : name === "windows" ? "Flash the taskbar icon" : "Ask for attention";
40+ byId("flash-label").textContent = name === "macos" ? "Bounce the dock icon" : name === "windows" ? "Flash the taskbar icon" : "Ask for attention";
4241 // macOS keeps its menu bar at the top of the screen, whichever title bar the window has.
4342 if (name === "macos") byId("system-title-bar-note").textContent = "In place of g1t's own, which sits under the window's buttons.";
4443 if (name === "macos") byId("zoom-note").textContent = "The View menu changes it too: ⌘+, ⌘− and ⌘0.";
8887 return settings;
8988 }
9089
91−
9290 function save() {
9391 invoke("get_settings")
9492 .then(function (fresh) {
10199 }
102100
103101 byId("open-runner").addEventListener("click", function () {
104− window.g1tBusy.run(byId("open-runner"), "open-runner", "", false, function () {
105− return invoke("runner_control", { action: "open_runner" });
106− }, fail);
102+ window.g1tBusy.run(
103+ byId("open-runner"),
104+ "open-runner",
105+ "",
106+ false,
107+ function () {
108+ return invoke("runner_control", { action: "open_runner" });
109+ },
110+ fail,
111+ );
107112 });
108113
109114 SWITCHES.forEach(function (key) {
157162 })
158163 .catch(function (error) {
159164 var text = typeof error === "string" ? error : "";
160− status.textContent = /sending request|connect|dns|timed out/i.test(text) || !text
161− ? "Could not reach g1t.sh to check. Check your connection and try again."
162− : "Could not check: " + text;
165+ status.textContent =
166+ /sending request|connect|dns|timed out/i.test(text) || !text
167+ ? "Could not reach g1t.sh to check. Check your connection and try again."
168+ : "Could not check: " + text;
163169 })
164170 .then(function () {
165171 checking = false;
204210 });
205211
206212 byId("change-server").addEventListener("click", function () {
207− window.g1tBusy.run(byId("change-server"), "change-server", "", false, function () {
208− return invoke("change_server");
209− }, fail);
213+ window.g1tBusy.run(
214+ byId("change-server"),
215+ "change-server",
216+ "",
217+ false,
218+ function () {
219+ return invoke("change_server");
220+ },
221+ fail,
222+ );
210223 });
211224
212225 // Links out, in the system's browser (src/bridge.js does the same on the site).
+107−102
11 /* The title bar, in the colours of the page under it (titlebar.js sets
22 them): g1t's rail on g1t's pages, light or dark. 36px tall. */
33 :root {
4− --bg: #050507;
5− --fg: #ededef;
6− --muted: #a0a0a8;
7− --accent: #b6a8ff;
8− --hover: rgba(237, 237, 239, 0.1);
9− --pill: rgba(237, 237, 239, 0.09);
10− --pill-hover: rgba(237, 237, 239, 0.14);
11− --pill-edge: rgba(237, 237, 239, 0.08);
4+ --bg: #050507;
5+ --fg: #ededef;
6+ --muted: #a0a0a8;
7+ --accent: #b6a8ff;
8+ --hover: rgba(237, 237, 239, 0.1);
9+ --pill: rgba(237, 237, 239, 0.09);
10+ --pill-hover: rgba(237, 237, 239, 0.14);
11+ --pill-edge: rgba(237, 237, 239, 0.08);
1212 }
1313 * {
14− box-sizing: border-box;
14+ box-sizing: border-box;
1515 }
1616 html,
1717 body {
18− height: 100%;
19− margin: 0;
20− overflow: hidden;
21− background: var(--bg);
18+ height: 100%;
19+ margin: 0;
20+ overflow: hidden;
21+ background: var(--bg);
2222 }
2323 .bar {
24− height: 100%;
25− display: flex;
26− align-items: center;
27− gap: 2px;
28− padding-left: 6px;
29− color: var(--muted);
30− font: 500 12px/1 system-ui, "Segoe UI", -apple-system, Roboto, sans-serif;
31− user-select: none;
32− -webkit-user-select: none;
33− cursor: default;
24+ height: 100%;
25+ display: flex;
26+ align-items: center;
27+ gap: 2px;
28+ padding-left: 6px;
29+ color: var(--muted);
30+ font:
31+ 500 12px/1 system-ui,
32+ "Segoe UI",
33+ -apple-system,
34+ Roboto,
35+ sans-serif;
36+ user-select: none;
37+ -webkit-user-select: none;
38+ cursor: default;
3439 }
3540 .mac .bar {
36− padding-left: 78px;
41+ padding-left: 78px;
3742 }
3843 .side {
39− display: flex;
40− align-items: center;
41− gap: 2px;
42− flex: 1 1 0;
43− /* Never narrower than its buttons: the search shrinks instead. */
44− min-width: min-content;
44+ display: flex;
45+ align-items: center;
46+ gap: 2px;
47+ flex: 1 1 0;
48+ /* Never narrower than its buttons: the search shrinks instead. */
49+ min-width: min-content;
4550 }
4651 .end {
47− justify-content: flex-end;
52+ justify-content: flex-end;
4853 }
4954 .middle {
50− flex: 0 1 560px;
51− min-width: 0;
52− display: flex;
53− justify-content: center;
55+ flex: 0 1 560px;
56+ min-width: 0;
57+ display: flex;
58+ justify-content: center;
5459 }
5560 button {
56− all: unset;
57− box-sizing: border-box;
58− display: inline-flex;
59− align-items: center;
60− justify-content: center;
61− color: inherit;
61+ all: unset;
62+ box-sizing: border-box;
63+ display: inline-flex;
64+ align-items: center;
65+ justify-content: center;
66+ color: inherit;
6267 }
6368 .icon {
64− width: 28px;
65− height: 26px;
66− border-radius: 6px;
69+ width: 28px;
70+ height: 26px;
71+ border-radius: 6px;
6772 }
6873 .icon:hover {
69− background: var(--hover);
70− color: var(--fg);
74+ background: var(--hover);
75+ color: var(--fg);
7176 }
7277 .icon:disabled {
73− opacity: 0.35;
74− background: none;
75− color: inherit;
78+ opacity: 0.35;
79+ background: none;
80+ color: inherit;
7681 }
7782 .search {
78− width: 100%;
79− height: 24px;
80− gap: 8px;
81− padding: 0 10px;
82− justify-content: flex-start;
83− border-radius: 6px;
84− background: var(--pill);
85− box-shadow: inset 0 0 0 1px var(--pill-edge);
83+ width: 100%;
84+ height: 24px;
85+ gap: 8px;
86+ padding: 0 10px;
87+ justify-content: flex-start;
88+ border-radius: 6px;
89+ background: var(--pill);
90+ box-shadow: inset 0 0 0 1px var(--pill-edge);
8691 }
8792 .search:hover {
88− background: var(--pill-hover);
89− color: var(--fg);
93+ background: var(--pill-hover);
94+ color: var(--fg);
9095 }
9196 .search span,
9297 .title {
93− overflow: hidden;
94− text-overflow: ellipsis;
95− white-space: nowrap;
98+ overflow: hidden;
99+ text-overflow: ellipsis;
100+ white-space: nowrap;
96101 }
97102 .title {
98− padding: 0 8px;
103+ padding: 0 8px;
99104 }
100105 .caption {
101− width: 46px;
102− height: 36px;
106+ width: 46px;
107+ height: 36px;
103108 }
104109 .caption:hover {
105− background: var(--hover);
106− color: var(--fg);
110+ background: var(--hover);
111+ color: var(--fg);
107112 }
108113 .caption.close:hover {
109− background: #c42b1c;
110− color: #fff;
114+ background: #c42b1c;
115+ color: #fff;
111116 }
112117 button:focus-visible {
113− outline: 2px solid var(--accent);
114− outline-offset: -2px;
118+ outline: 2px solid var(--accent);
119+ outline-offset: -2px;
115120 }
116121 /* The runner: a dot in its tone, right beside the settings, the size of
117122 an icon button. A wide window has room for what it is doing too. Its
118123 menu hangs under it, drawn by the page below (the site). */
119124 .chip {
120− gap: 7px;
121− min-width: 28px;
122− height: 26px;
123− padding: 0 10px;
124− border-radius: 6px;
125− white-space: nowrap;
125+ gap: 7px;
126+ min-width: 28px;
127+ height: 26px;
128+ padding: 0 10px;
129+ border-radius: 6px;
130+ white-space: nowrap;
126131 }
127132 .chip[hidden] {
128− display: none;
133+ display: none;
129134 }
130135 .chip:hover,
131136 .chip[aria-expanded="true"] {
132− background: var(--hover);
133− color: var(--fg);
137+ background: var(--hover);
138+ color: var(--fg);
134139 }
135140 .chip-dot {
136− width: 8px;
137− height: 8px;
138− flex: none;
139− border-radius: 50%;
140− background: var(--muted);
141+ width: 8px;
142+ height: 8px;
143+ flex: none;
144+ border-radius: 50%;
145+ background: var(--muted);
141146 }
142147 .chip[data-tone="ok"] .chip-dot {
143− background: #4ade80;
148+ background: #4ade80;
144149 }
145150 .chip[data-tone="working"] .chip-dot {
146− background: #60a5fa;
147− animation: breathe 1.6s ease-in-out infinite;
151+ background: #60a5fa;
152+ animation: breathe 1.6s ease-in-out infinite;
148153 }
149154 .chip[data-tone="warning"] .chip-dot {
150− background: #fbbf24;
155+ background: #fbbf24;
151156 }
152157 .chip[data-tone="problem"] .chip-dot {
153− background: #f87171;
158+ background: #f87171;
154159 }
155160 .chip[data-tone="off"] .chip-dot {
156− background: var(--muted);
157− opacity: 0.6;
161+ background: var(--muted);
162+ opacity: 0.6;
158163 }
159164 @keyframes breathe {
160− 50% {
161− opacity: 0.35;
162− }
165+ 50% {
166+ opacity: 0.35;
167+ }
163168 }
164169 @media (prefers-reduced-motion: reduce) {
165− .chip[data-tone="working"] .chip-dot {
166− animation: none;
167− }
170+ .chip[data-tone="working"] .chip-dot {
171+ animation: none;
172+ }
168173 }
169174 /* The dot alone, until the window is wide enough that the words fit
170175 beside it without crowding the search. */
171176 .chip-text {
172− display: none;
177+ display: none;
173178 }
174179 @media (min-width: 1360px) {
175− .chip-text {
176− display: inline;
177− }
180+ .chip-text {
181+ display: inline;
182+ }
178183 }
+14−14
66 its buttons act on the window and on that page through the app.
77 -->
88 <html lang="en">
9− <head>
10− <meta charset="utf-8" />
11− <meta name="viewport" content="width=device-width, initial-scale=1" />
12− <title>g1t</title>
13− <link rel="stylesheet" href="titlebar.css" />
14− </head>
15− <body>
16− <div class="bar" id="bar" role="toolbar" aria-label="Window">
17− <div class="side" id="left"></div>
18− <div class="middle" id="middle"></div>
19− <div class="side end" id="right"></div>
20− </div>
21− <script src="titlebar.js"></script>
22− </body>
9+ <head>
10+ <meta charset="utf-8" />
11+ <meta name="viewport" content="width=device-width, initial-scale=1" />
12+ <title>g1t</title>
13+ <link rel="stylesheet" href="titlebar.css" />
14+ </head>
15+ <body>
16+ <div class="bar" id="bar" role="toolbar" aria-label="Window">
17+ <div class="side" id="left"></div>
18+ <div class="middle" id="middle"></div>
19+ <div class="side end" id="right"></div>
20+ </div>
21+ <script src="titlebar.js"></script>
22+ </body>
2323 </html>
+9−4
3636 back: svg('<polyline points="9.5,3.5 5,8 9.5,12.5"/><line x1="5" y1="8" x2="13" y2="8"/>'),
3737 forward: svg('<polyline points="6.5,3.5 11,8 6.5,12.5"/><line x1="3" y1="8" x2="11" y2="8"/>'),
3838 search: svg('<circle cx="7" cy="7" r="4"/><line x1="10" y1="10" x2="13" y2="13"/>'),
39− settings: svg('<line x1="2.5" y1="4.5" x2="13.5" y2="4.5"/><line x1="2.5" y1="11.5" x2="13.5" y2="11.5"/><circle cx="10" cy="4.5" r="1.75" fill="var(--bg)"/><circle cx="6" cy="11.5" r="1.75" fill="var(--bg)"/>'),
39+ settings: svg(
40+ '<line x1="2.5" y1="4.5" x2="13.5" y2="4.5"/><line x1="2.5" y1="11.5" x2="13.5" y2="11.5"/><circle cx="10" cy="4.5" r="1.75" fill="var(--bg)"/><circle cx="6" cy="11.5" r="1.75" fill="var(--bg)"/>',
41+ ),
4042 minimize: svg('<line x1="3.5" y1="8" x2="12.5" y2="8"/>'),
4143 maximize: svg('<rect x="3.5" y="3.5" width="9" height="9" rx="1"/>'),
4244 restore: svg('<rect x="3.5" y="5.5" width="7" height="7" rx="1"/><path d="M5.5 5.5V4.5a1 1 0 0 1 1-1h5a1 1 0 0 1 1 1v5a1 1 0 0 1-1 1h-1"/>'),
217219 })
218220 .catch(function () {});
219221 }
220− invoke("runner_status").then(function (view) {
221− drawChip(view && view.chip);
222− }, function () {});
222+ invoke("runner_status").then(
223+ function (view) {
224+ drawChip(view && view.chip);
225+ },
226+ function () {},
227+ );
223228 })();
+46−52
11 {
2− "$schema": "https://schema.tauri.app/config/2",
3− "productName": "g1t",
4− "identifier": "sh.g1t.desktop",
5− "build": {
6− "frontendDist": "../launcher"
7− },
8− "app": {
9− "withGlobalTauri": true,
10− "windows": [],
11− "security": {
12− "csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
13− }
14− },
15− "bundle": {
16− "active": true,
17− "targets": "all",
18− "createUpdaterArtifacts": true,
19− "icon": [
20− "icons/32x32.png",
21− "icons/128x128.png",
22− "icons/128x128@2x.png",
23− "icons/icon.icns",
24− "icons/icon.ico"
25− ],
26− "category": "DeveloperTool",
27− "shortDescription": "g1t on your desktop",
28− "longDescription": "g1t in a window of its own: chat, artifacts and code, with notifications from your system, a badge on the icon, g1t:// links and updates that install themselves.",
29− "publisher": "Flagon, Inc.",
30− "copyright": "Flagon, Inc.",
31− "homepage": "https://g1t.sh",
32− "windows": {
33− "webviewInstallMode": { "type": "downloadBootstrapper" },
34− "nsis": {
35− "installMode": "currentUser",
36− "installerHooks": "./windows/hooks.nsh",
37− "languages": ["English"]
38− }
39− },
40− "macOS": {
41− "minimumSystemVersion": "11.0"
42− }
43− },
44− "plugins": {
45− "updater": {
46− "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDdDMEU2MjkxRkU5N0RBRUMKUldUczJwZitrV0lPZkZVckJFeXdhMUMyN2s3a2VoZ2VYRkZESFBhQkY5UnBuS3RhbkNIbEU3bVMK",
47− "endpoints": ["https://g1t.sh/downloads/desktop/latest.json"],
48− "windows": { "installMode": "passive" }
49− },
50− "deep-link": {
51− "desktop": { "schemes": ["g1t"] }
52− }
53− }
2+ "$schema": "https://schema.tauri.app/config/2",
3+ "productName": "g1t",
4+ "identifier": "sh.g1t.desktop",
5+ "build": {
6+ "frontendDist": "../launcher"
7+ },
8+ "app": {
9+ "withGlobalTauri": true,
10+ "windows": [],
11+ "security": {
12+ "csp": "default-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:"
13+ }
14+ },
15+ "bundle": {
16+ "active": true,
17+ "targets": "all",
18+ "createUpdaterArtifacts": true,
19+ "icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"],
20+ "category": "DeveloperTool",
21+ "shortDescription": "g1t on your desktop",
22+ "longDescription": "g1t in a window of its own: chat, artifacts and code, with notifications from your system, a badge on the icon, g1t:// links and updates that install themselves.",
23+ "publisher": "Flagon, Inc.",
24+ "copyright": "Flagon, Inc.",
25+ "homepage": "https://g1t.sh",
26+ "windows": {
27+ "webviewInstallMode": { "type": "downloadBootstrapper" },
28+ "nsis": {
29+ "installMode": "currentUser",
30+ "installerHooks": "./windows/hooks.nsh",
31+ "languages": ["English"]
32+ }
33+ },
34+ "macOS": {
35+ "minimumSystemVersion": "11.0"
36+ }
37+ },
38+ "plugins": {
39+ "updater": {
40+ "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDdDMEU2MjkxRkU5N0RBRUMKUldUczJwZitrV0lPZkZVckJFeXdhMUMyN2s3a2VoZ2VYRkZESFBhQkY5UnBuS3RhbkNIbEU3bVMK",
41+ "endpoints": ["https://g1t.sh/downloads/desktop/latest.json"],
42+ "windows": { "installMode": "passive" }
43+ },
44+ "deep-link": {
45+ "desktop": { "schemes": ["g1t"] }
46+ }
47+ }
5448 }
+315−320
Loading the diff…
+246−248
Loading the diff…
+31−31
Loading the diff…
+6−6
Loading the diff…
+73−73
Loading the diff…
+11−11
Loading the diff…
+12−12
Loading the diff…
+14−14
Loading the diff…
+4−1
Loading the diff…
+8−4
Loading the diff…
+85−18
Loading the diff…
+85−17
Loading the diff…
+3−1
Loading the diff…
+7−1
Loading the diff…
+68−13
Loading the diff…
+121−36
Loading the diff…
+60−10
Loading the diff…
+2−10
Loading the diff…
+21−3
Loading the diff…
+2−7
Loading the diff…
+40−16
Loading the diff…
+10−3
Loading the diff…
+61−19
Loading the diff…
+37−5
Loading the diff…
+7−1
Loading the diff…
+2−1
Loading the diff…
+2−7
Loading the diff…
+78−78
Loading the diff…
+5−5
Loading the diff…
+1−6
Loading the diff…
+3−8
Loading the diff…
+1−6
Loading the diff…
+1−4
Loading the diff…
+1−5
Loading the diff…
+1−4
Loading the diff…
+48−48
Loading the diff…
+4−4
Loading the diff…
+105−40
Loading the diff…
+70−222
Loading the diff…
+3−5
Loading the diff…
+76−31
Loading the diff…
+23−3
Loading the diff…
+1−8
Loading the diff…
+1−4
Loading the diff…
+14−8
Loading the diff…
+14−5
Loading the diff…
+6−1
Loading the diff…
+74−74
Loading the diff…
+10−10
Loading the diff…
+34−8
Loading the diff…
+11−5
Loading the diff…
+3−18
Loading the diff…
+17−5
Loading the diff…
+89−18
Loading the diff…
+104−20
Loading the diff…
+109−59
Loading the diff…
+73−23
Loading the diff…
+89−32
Loading the diff…
+119−56
Loading the diff…
+286−55
Loading the diff…
+12−6
Loading the diff…
+23−9
Loading the diff…
+1−1
Loading the diff…
+24−4
Loading the diff…
+143−810
A large diff (1,640 lines) is not shown until you ask for it.
+4−7
Loading the diff…
+4−10
Loading the diff…
+1−2
Loading the diff…
+339−344
Loading the diff…
+344−316
Loading the diff…
+1−3
Loading the diff…
+1−7
Loading the diff…
+4−27
Loading the diff…
+92−26
Loading the diff…
+1−10
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…
Loading the diff…

More files changed than one page lists: these are the first 300.

Comments

Sign in to comment.