Add user-local project icons - #4401
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Needs human review This PR introduces a complete new feature (user-local project icons) with new UI components, settings schema, server-side resolution logic, and context menu integrations. The ~1500 lines of new functionality introducing new user-facing workflows warrants human review. You can customize Macroscope's approvability policy. Learn more. |
73ce479 to
2093b5b
Compare
81db661 to
8e65d17
Compare
804efc4 to
5c2c09c
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 5c2c09c. Configure here.
5c2c09c to
9759616
Compare
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
Manifests and locks updated to the current stack (pingdotgg#4505 subsumed, pingdotgg#4401 resolved at source). BUILDING.md gains a pre-build syntax gate: esbuild parses TSX in seconds with an exact location, where a nix build takes minutes and Babel surfaces only the first parse error per file.
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
9759616 to
3c065dd
Compare
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx # packages/contracts/src/settings.test.ts # packages/shared/src/serverSettings.ts
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx # packages/contracts/src/settings.test.ts # packages/shared/src/serverSettings.ts
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx # packages/contracts/src/settings.test.ts # packages/shared/src/serverSettings.ts
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx # packages/contracts/src/settings.test.ts # packages/shared/src/serverSettings.ts
3c065dd to
1e28730
Compare
1e28730 to
6f052c8
Compare
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx
# Conflicts: # apps/server/src/assets/AssetAccess.test.ts # apps/web/src/components/CommandPalette.tsx # apps/web/src/components/ProjectFavicon.tsx # apps/web/src/components/Sidebar.logic.test.ts # apps/web/src/components/SidebarV2.tsx

What Changed
projectIconsandprojectIconsByGitRemotemaps to the serversettings.json, keyed by workspace root or normalized repository identity.~/…), or project-relative. They overridet3.jsonand automatic favicon discovery without changing the repository.Why
Project icons are currently discovered from files committed to each repository. Personal project organization should not require adding app-specific assets or metadata to the project itself. Git-remote keys also make a dotfile-backed setting portable across devices and clone paths while retaining exact-path overrides for worktrees or exceptional clones.
UI Changes
Before — automatic folder icon:
After — right-clicking the Sidebar v2 thread icon exposes the action:
After — the dialog shows the configured external icon and the persistent settings file:
After — a second clone at a different path inherits the normalized git-remote icon:
Checklist
vp checkvp run typecheckvp test run packages/contracts/src/settings.test.ts packages/shared/src/serverSettings.test.ts apps/server/src/project/ProjectFaviconResolver.test.ts apps/server/src/assets/AssetAccess.test.ts apps/server/src/serverSettings.test.ts apps/web/src/components/ProjectIconSettings.test.tssettings.json, and a signed SVG asset outside the repository.github.com/pingdotgg/t3codeicon setting renders for two clones at different local paths.Note
Add user-local project icons configurable from the sidebar and project settings
ProjectIconDialogfor setting a custom icon path per workspace or per git remote.ProjectFaviconResolverto acceptcustomIconPaths(absolute,~-relative, or workspace-relative) and return a source discriminator (custom-settingvsworkspace).AssetAccess.issueAssetUrlto readprojectIcons/projectIconsByGitRemotefromServerSettingsandRepositoryIdentityResolverto resolve git-remote-scoped icons; issues v2project-iconclaims with an absolute path.projectIconsandprojectIconsByGitRemotemaps toServerSettingsandServerSettingsPatch, with atomic update support viaprojectIconUpdate.ProjectFaviconnow computes a deterministicconfiguredIconRevisionhash from current icon settings and passes it to asset URL requests for cache-busting.resolveAssetfor v2 tokens re-canonicalizes the signed absolute path at resolution time and returnsnullif the file has been replaced by a symlink or moved.Macroscope summarized 6f052c8.
Note
Medium Risk
Touches signed asset serving and path canonicalization for files outside the workspace; misconfiguration or symlink races are mitigated by tests but remain security-sensitive surface area.
Overview
Adds user-local project icons stored in server
settings.json, without changing the repository. Users can set a custom icon path per workspace root or per normalized git remote so the same icon follows clones on other machines and paths.Server & contracts: New
projectIconsandprojectIconsByGitRemotemaps plus atomicprojectIconUpdatepatches.ProjectFaviconResolvergainscustomIconPaths(absolute,~/…, or project-relative) and returns whether the icon came from a custom setting vs workspace discovery.AssetAccessreads those settings and repository identity, issues v2project-iconsigned tokens with a canonical absolute path for configured icons outside the repo, and still enforces workspace containment for auto-discovered icons (including rejecting post-sign symlink swaps).Web UI:
ProjectIconDialog/ inline path field in Sidebar v2 project settings; classic sidebar context menu Project icon…; Sidebar v2 right-click on the thread favicon to set/change.ProjectFaviconpasses a bounded settings revision on asset requests for cache-busting when icon maps or repository identity change.Reviewed by Cursor Bugbot for commit 6f052c8. Bugbot is set up for automated code reviews on this repo. Configure here.
Current combined-stack UI evidence (2026-07-24)
Captured from PR head
804efc44c5a8321667f51400b3c513af593cde82on upstream mainece05087a70e94efcd57441337fa1249559362ba, using combined integration4dd4cef40and package/nix/store/pf7fjqw8ykkdgayf3ywsbgxxp6wi1m42-t3code-0.0.29-patched-main-20260724.The settings capture shows an external SVG stored by normalized remote identity for every clone; the second capture shows the resulting custom tree icon in Sidebar V2 and the draft header. All names, remotes, paths, and assets are disposable seed data.