Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bench/baseline/sizes.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
"recorded_at": "2026-08-20T20:12:18.316Z"
},
"frontend:initial": {
"bytes": 845843,
"recorded_at": "2026-09-07T14:38:04.389Z"
"bytes": 538600,
"recorded_at": "2026-09-17T19:06:00.357Z"
}
},
"startup": {
Expand Down
13 changes: 13 additions & 0 deletions gg-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,19 @@ pnpm --filter gg-app test # vitest
pnpm --filter gg-app lint
```

## Project colour tags

Click the colour button beside an open project's name to choose a personal colour.
**Automatic** restores the generated accent; **None** removes the decoration without
hiding the button. **Show header stripe** adds an app-wide stripe and is off by default.
None suppresses the stripe for that project.

Choices belong to the full project folder path, so same-named folders stay separate.
Native windows share preferences in `~/.gg/gg-app-project-colours.json`, independently
of other app settings. These preferences are personal, survive restarts, and are not
written into the project or shared with teammates. Browser previews use local storage
instead; they do not share the native app's preferences.

## Architecture

Each window runs its **own** Node agent sidecar pointed at its **own** project folder.
Expand Down
48 changes: 48 additions & 0 deletions gg-app/scripts/markdown-split.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { mkdtempSync, readFileSync, rmSync, statSync } from "node:fs";
import { tmpdir } from "node:os";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { spawnSync } from "node:child_process";
import { expect, it } from "vitest";

it("keeps rich-text rendering outside startup and production JS chunks below the warning limit", () => {
const out = mkdtempSync(path.join(tmpdir(), "gg-markdown-split-"));
try {
// Run the installed JS entry with Node, not a platform-specific pnpm shim.
const viteCli = fileURLToPath(new URL("../node_modules/vite/bin/vite.js", import.meta.url));
const build = spawnSync(
process.execPath,
[viteCli, "build", "--outDir", out, "--emptyOutDir"],
{
cwd: fileURLToPath(new URL("../", import.meta.url)),
encoding: "utf8",
// Vitest sets NODE_ENV=test; measure the shipped React build instead.
env: { ...process.env, NODE_ENV: "production" },
timeout: 30_000,
},
);
expect(build.error).toBeUndefined();
expect(build.status, build.stdout + build.stderr).toBe(0);
const manifest = JSON.parse(readFileSync(path.join(out, ".vite/manifest.json"), "utf8"));
expect(manifest["src/MarkdownRenderer.tsx"].isDynamicEntry).toBe(true);
const initial = new Set();
function visit(key) {
if (initial.has(key)) return;
initial.add(key);
for (const imported of manifest[key].imports ?? []) visit(imported);
}
for (const [key, chunk] of Object.entries(manifest)) if (chunk.isEntry) visit(key);
expect(initial.has("src/MarkdownRenderer.tsx")).toBe(false);
for (const chunk of Object.values(manifest)) {
if (chunk.file.endsWith(".js"))
expect(statSync(path.join(out, chunk.file)).size, chunk.file).toBeLessThanOrEqual(500_000);
}
const initialBytes = [...initial].reduce(
(bytes, key) => bytes + statSync(path.join(out, manifest[key].file)).size,
0,
);
expect(initialBytes).toBeLessThan(600_000);
} finally {
rmSync(out, { recursive: true, force: true });
}
}, 35_000);
5 changes: 5 additions & 0 deletions gg-app/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use std::process::{Child, Command, Stdio};
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use std::sync::Mutex;

mod project_colours;

#[cfg(unix)]
use std::os::unix::process::CommandExt;
#[cfg(windows)]
Expand Down Expand Up @@ -5088,6 +5090,7 @@ pub fn run() {
..Default::default()
})
.manage(Windows::default())
.manage(project_colours::ProjectColours::default())
.manage(RestoreTargets::default())
.manage(AppExiting::default())
.manage(FocusedWindow::default())
Expand Down Expand Up @@ -5156,6 +5159,8 @@ pub fn run() {
agent_set_project_hidden,
app_settings_get,
app_settings_save,
project_colours::project_colours_get,
project_colours::project_colours_save,
app_create_project,
app_auth_status,
app_auth_apikey,
Expand Down
Loading