Repository navigation
feat(desktop,host-service): v2 project colors — icon+color picker and v1 import carry-over - #6249
Conversation
… import carry-over - host-service: add projects.color column (migration 0015), thread it through ProjectSnapshot / project.list / project.get, and add a project.setColor mutation mirroring setIcon - v1→v2 import: carry the v1 accent color onto the imported v2 project (best-effort, both the auto-migrator and the wizard path via importV1Project); 'default' sentinel stays unset - v2 settings: extend IconUploadField into a simple icon+color picker — color swatches (ColorSelector) plus a lucide glyph grid baked into the existing setIcon data-URI path, alongside upload/reset - render the accent color on the v2 ProjectThumbnail (tinted border and letter fallback, matching v1) in project settings, the settings project list, and the dashboard sidebar The 'Remove icon' tRPC error (v2/project/removeIcon) was already fixed on main by #5845; no call sites remain and reset goes through project.setIcon(null).
🚀 Preview Deployment🔗 Preview Links
Preview updates automatically with new commits |
Greptile SummaryThe PR adds host-local project accent colors, an icon-and-color picker, color propagation through project snapshots/sidebar rendering, and v1 migration carry-over.
Confidence Score: 3/5The PR should not merge until already-linked v1 projects receive color carry-over and failed color writes stop triggering dependent icon updates. The migration permanently skips a required color side effect for already-linked projects, while the picker can partially apply a failed color selection by persisting a mismatched baked icon. Files Needing Attention: apps/desktop/src/renderer/lib/v1-migration/projects.ts; apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx
|
| Filename | Overview |
|---|---|
| apps/desktop/src/renderer/lib/v1-migration/projects.ts | Adds best-effort color carry-over, but only importV1Project callers receive it, excluding already-linked projects. |
| apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx | Adds the icon/color popover and glyph rasterization, but continues the dependent glyph write after a color mutation failure. |
| packages/host-service/src/trpc/router/project/project.ts | Adds a validated setColor mutation and threads color through project list/get snapshots. |
| apps/desktop/src/renderer/hooks/host-projects/useHostProjects/useHostProjects.utils.ts | Normalizes and merges color through live and persisted host project rows; remote replica precedence remains host-order-dependent. |
| packages/host-service/drizzle/0015_special_green_goblin.sql | Adds the nullable project color column through an additive SQLite migration. |
Sequence Diagram
sequenceDiagram
participant UI as Desktop picker/import
participant Host as Host-service project router
participant DB as Host SQLite
participant Events as project:changed
participant Sidebar as Renderer project views
UI->>Host: setColor(projectId, color)
Host->>DB: update projects.color
Host->>Events: broadcast updated snapshot
Events->>Sidebar: merge color into project cache
Sidebar-->>UI: render tinted thumbnail
Prompt To Fix All With AI
### Issue 1
apps/desktop/src/renderer/lib/v1-migration/projects.ts:131
**Linked projects lose migrated colors**
When a v1 repository is already registered as a local v2 project, the migration records it as linked without calling `importV1Project`, so `carryV1ProjectColor` never runs and the terminal ledger status prevents a later pass from restoring the v1 accent.
### Issue 2
apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx:202-206
**Failed colors still rewrite icons**
When `project.setColor` fails after a glyph was selected, `setColor` catches the error and resolves, so this code still persists a glyph baked with the rejected color. On an older host where `setColor` is unavailable but `setIcon` works, the user sees an error while the icon changes and diverges from the stored accent.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "feat(desktop,host-service): v2 project c..." | Re-trigger Greptile
| allowRelocate, | ||
| }, | ||
| }); | ||
| await carryV1ProjectColor(hostClient, targetCandidate.id, project.color); |
There was a problem hiding this comment.
Linked projects lose migrated colors
When a v1 repository is already registered as a local v2 project, the migration records it as linked without calling importV1Project, so carryV1ProjectColor never runs and the terminal ledger status prevents a later pass from restoring the v1 accent.
Knowledge Base Used: Desktop App (Electron main + renderer)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/lib/v1-migration/projects.ts
Line: 131
Comment:
**Linked projects lose migrated colors**
When a v1 repository is already registered as a local v2 project, the migration records it as linked without calling `importV1Project`, so `carryV1ProjectColor` never runs and the terminal ledger status prevents a later pass from restoring the v1 accent.
**Knowledge Base Used:** [Desktop App (Electron main + renderer)](https://app.greptile.com/personal-org-6810/-/custom-context/knowledge-base/superset-sh/superset/-/docs/desktop-app.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Intended behavior, not a drop: the linked outcome means the repo is already a v2 project on this host — often one the user has since configured in v2, so re-carrying the v1 color there could clobber a v2 choice on every migration pass. The carry deliberately runs only when the import actually sets the project up on this host (both the setup-link and create branches inside importV1Project). Documented in the PR under Known Limitations / Design Decisions.
There was a problem hiding this comment.
That's a sound rationale — re-carrying v1 color on every pass over an already-linked v2 project would silently overwrite any color the user chose in v2. Running carryV1ProjectColor only on the setup paths (create and setup-link inside importV1Project) is the right call. Acknowledged.
| await setColor(nextColor); | ||
| // Keep a glyph picked this session in sync with the new color. | ||
| if (sessionGlyph) { | ||
| try { | ||
| await setIcon(await glyphToDataUri(sessionGlyph, nextColor)); |
There was a problem hiding this comment.
Failed colors still rewrite icons
When project.setColor fails after a glyph was selected, setColor catches the error and resolves, so this code still persists a glyph baked with the rejected color. On an older host where setColor is unavailable but setIcon works, the user sees an error while the icon changes and diverges from the stored accent.
Knowledge Base Used: Desktop App (Electron main + renderer)
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx
Line: 202-206
Comment:
**Failed colors still rewrite icons**
When `project.setColor` fails after a glyph was selected, `setColor` catches the error and resolves, so this code still persists a glyph baked with the rejected color. On an older host where `setColor` is unavailable but `setIcon` works, the user sees an error while the icon changes and diverges from the stored accent.
**Knowledge Base Used:** [Desktop App (Electron main + renderer)](https://app.greptile.com/personal-org-6810/-/custom-context/knowledge-base/superset-sh/superset/-/docs/desktop-app.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.There was a problem hiding this comment.
Fixed in 7436c49: setColor/setIcon now return success, and handleSelectColor only re-bakes the session glyph when the color actually persisted — a rejected color (offline host, old host without setColor) no longer re-tints the icon. Swatches are also disabled while a mutation is pending so rapid clicks can't land out of order.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (6)
📝 WalkthroughWalkthroughThe change adds nullable project colors to host storage, APIs, project synchronization, v1 migration, thumbnails, sidebars, and project settings. It also adds explicit no-icon handling and a combined color and icon editor. ChangesProject accent color
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant V2ProjectSettings
participant IconUploadField
participant ProjectRouter
participant LocalProjectStore
V2ProjectSettings->>IconUploadField: provide color and icon state
IconUploadField->>ProjectRouter: setColor or setIcon
ProjectRouter->>LocalProjectStore: persist project appearance
LocalProjectStore-->>ProjectRouter: return updated ProjectSnapshot
ProjectRouter-->>IconUploadField: return persisted appearance
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
apps/desktop/src/renderer/lib/v1-migration/runV1Migration.test.ts (1)
113-117: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd
project.setColortoALLOWED_MUTATIONS.The fake host now records a
project.setColormutation. TheALLOWED_MUTATIONSset at lines 408-415 does not list it. Existing tests still pass because every other fixture uses the"default"sentinel and therefore emits nosetColorcall. A future test that uses a hex-colored fixture would fail against the allowlist for an unrelated reason.♻️ Proposed fix
const ALLOWED_MUTATIONS = new Set([ "project.setup", "project.create", + "project.setColor", "project.setWorktreeBaseDir", "project.setBranchPrefix", "settings.branchPrefix.set", "workspaceCreation.adopt", ]);🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@apps/desktop/src/renderer/lib/v1-migration/runV1Migration.test.ts` around lines 113 - 117, Add "project.setColor" to the ALLOWED_MUTATIONS set used by the fake host in runV1Migration tests, preserving the existing mutation validation and allowing recorded color mutations from setColor.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@apps/desktop/src/renderer/routes/_authenticated/components/ProjectThumbnail/ProjectThumbnail.tsx`:
- Around line 7-21: Update isHexColor to accept only complete `#rrggbb` values
with exactly six hexadecimal digits; treat all other inputs as unset. Ensure the
hasColor styling branch and hexToRgba usage rely on this validated result so
invalid colors retain the muted fallback classes and never produce NaN
components.
In
`@apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/`$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx:
- Around line 271-277: Disable color selection while a color mutation is
pending: in IconUploadField.tsx lines 271-277, pass disabled={disabled} to
ColorSelector; in ColorSelector.tsx lines 11-16, add the disabled prop; and in
lines 86-100, apply it to every swatch button and the menu variant.
- Around line 166-213: Update setColor to return a success result only when
project.setColor.mutate completes successfully, and return failure after
handling an error. In handleSelectColor, continue to the sessionGlyph re-bake
only when setColor reports success; preserve the existing pending-state cleanup
and error handling.
---
Nitpick comments:
In `@apps/desktop/src/renderer/lib/v1-migration/runV1Migration.test.ts`:
- Around line 113-117: Add "project.setColor" to the ALLOWED_MUTATIONS set used
by the fake host in runV1Migration tests, preserving the existing mutation
validation and allowing recorded color mutations from setColor.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 4a4254f7-720b-4823-aec9-dee9ec419f77
📒 Files selected for processing (24)
apps/desktop/src/renderer/components/ColorSelector/ColorSelector.tsxapps/desktop/src/renderer/hooks/host-projects/useHostProjects/useHostProjects.utils.tsapps/desktop/src/renderer/lib/v1-migration/ipc.tsapps/desktop/src/renderer/lib/v1-migration/projects.tsapps/desktop/src/renderer/lib/v1-migration/runV1Migration.test.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/DashboardSidebarProjectSection.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/components/DashboardSidebarCollapsedProjectContent/DashboardSidebarCollapsedProjectContent.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarProjectSection/components/DashboardSidebarProjectRow/DashboardSidebarProjectRow.tsxapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/hooks/useDashboardSidebarData/buildDashboardSidebarProjects.test.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/hooks/useDashboardSidebarData/buildDashboardSidebarProjects.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/hooks/useDashboardSidebarData/useDashboardSidebarData.tsapps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/types.tsapps/desktop/src/renderer/routes/_authenticated/components/ProjectThumbnail/ProjectThumbnail.tsxapps/desktop/src/renderer/routes/_authenticated/components/V1ImportModal/ImportProjectsPage/ImportProjectsPage.tsxapps/desktop/src/renderer/routes/_authenticated/settings/projects/components/ProjectsSettingsSidebar/ProjectsSettingsSidebar.tsxapps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsxapps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsxpackages/host-service/drizzle/0015_special_green_goblin.sqlpackages/host-service/drizzle/meta/0015_snapshot.jsonpackages/host-service/drizzle/meta/_journal.jsonpackages/host-service/src/db/schema.tspackages/host-service/src/events/types.tspackages/host-service/src/projects/local-project-store.tspackages/host-service/src/trpc/router/project/project.ts
There was a problem hiding this comment.
2 issues found across 24 files
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/src/renderer/routes/_authenticated/components/ProjectThumbnail/ProjectThumbnail.tsx">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/components/ProjectThumbnail/ProjectThumbnail.tsx:12">
P3: The new thumbnail copies the existing hex conversion and accent styling instead of sharing it, so validation or color-rendering fixes can diverge between v1 thumbnails, v2 thumbnails, and the picker. A shared color utility would keep these paths consistent.</violation>
</file>
<file name="apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx:166">
P3: `setColor` duplicates the full shape of `setIcon` (offline guard, `isPending` management, mutate + error toast + `finally` reset). Consider extracting a small shared helper (e.g. a generic `runProjectMutation(procedure, payload)` or a `useProjectIconMutation`/`useProjectColorMutation` hook) so these two flows can't drift apart as the mutation handling evolves.</violation>
</file>
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
| className?: string; | ||
| } | ||
|
|
||
| function hexToRgba(hex: string, alpha: number): string { |
There was a problem hiding this comment.
P3: The new thumbnail copies the existing hex conversion and accent styling instead of sharing it, so validation or color-rendering fixes can diverge between v1 thumbnails, v2 thumbnails, and the picker. A shared color utility would keep these paths consistent.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/components/ProjectThumbnail/ProjectThumbnail.tsx, line 12:
<comment>The new thumbnail copies the existing hex conversion and accent styling instead of sharing it, so validation or color-rendering fixes can diverge between v1 thumbnails, v2 thumbnails, and the picker. A shared color utility would keep these paths consistent.</comment>
<file context>
@@ -4,25 +4,42 @@ import { useState } from "react";
className?: string;
}
+function hexToRgba(hex: string, alpha: number): string {
+ const r = Number.parseInt(hex.slice(1, 3), 16);
+ const g = Number.parseInt(hex.slice(3, 5), 16);
</file context>
| [hostUrl, projectId], | ||
| ); | ||
|
|
||
| const setColor = useCallback( |
There was a problem hiding this comment.
P3: setColor duplicates the full shape of setIcon (offline guard, isPending management, mutate + error toast + finally reset). Consider extracting a small shared helper (e.g. a generic runProjectMutation(procedure, payload) or a useProjectIconMutation/useProjectColorMutation hook) so these two flows can't drift apart as the mutation handling evolves.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx, line 166:
<comment>`setColor` duplicates the full shape of `setIcon` (offline guard, `isPending` management, mutate + error toast + `finally` reset). Consider extracting a small shared helper (e.g. a generic `runProjectMutation(procedure, payload)` or a `useProjectIconMutation`/`useProjectColorMutation` hook) so these two flows can't drift apart as the mutation handling evolves.</comment>
<file context>
@@ -82,6 +163,55 @@ export function IconUploadField({
[hostUrl, projectId],
);
+ const setColor = useCallback(
+ async (nextColor: string | null) => {
+ if (!hostUrl) {
</file context>
…-style letter fallback - setIcon accepts a 'none' sentinel: explicitly no icon, suppressing the GitHub avatar fallback so every surface renders the first-letter tile (tinted by the project color) via resolveProjectIconUrl — v1's hide_image equivalent - picker gains 'Remove icon' (when any icon shows) alongside 'Reset to default'; the trigger thumbnail now renders ProjectThumbnail, so an icon-less project shows its letter tile instead of a placeholder - v1→v2 import carries hide_image as the 'none' icon
…hes while pending Review follow-ups (Greptile/CodeRabbit/cubic): - setIcon/setColor return success; a rejected color no longer re-bakes the session glyph into a color the project never stored, and a failed setIcon no longer marks the glyph as session-active - ColorSelector gains a disabled prop; the picker disables swatches during mutations so rapid clicks can't land out of order - ProjectThumbnail accepts only exact #rrggbb before tinting (hexToRgba slices fixed offsets; malformed values now render as unset)
There was a problem hiding this comment.
1 issue found across 12 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx">
<violation number="1" location="apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx:202">
P3: When a project's accent color is ever malformed (not exactly `#rrggbb` — for example shorter `#fff` values that this same PR's ProjectThumbnail change explicitly protects against), picking a glyph bakes it through `hexToRgba`, which slices fixed offsets and yields `rgba(NaN,…)` channels, so the generated PNG won't carry the intended color. The renderer's thumbnail was just hardened for this exact case (treat malformed colors as unset), but the glyph-bake path here still trusts the raw value. Consider normalizing the color (fall back to `DEFAULT_GLYPH_COLOR` for anything that isn't a valid hex) before calling `glyphToDataUri`, mirroring the `isHexColor` guard added in ProjectThumbnail.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| async (glyph: IconType) => { | ||
| let dataUri: string; | ||
| try { | ||
| dataUri = await glyphToDataUri(glyph, color); |
There was a problem hiding this comment.
P3: When a project's accent color is ever malformed (not exactly #rrggbb — for example shorter #fff values that this same PR's ProjectThumbnail change explicitly protects against), picking a glyph bakes it through hexToRgba, which slices fixed offsets and yields rgba(NaN,…) channels, so the generated PNG won't carry the intended color. The renderer's thumbnail was just hardened for this exact case (treat malformed colors as unset), but the glyph-bake path here still trusts the raw value. Consider normalizing the color (fall back to DEFAULT_GLYPH_COLOR for anything that isn't a valid hex) before calling glyphToDataUri, mirroring the isHexColor guard added in ProjectThumbnail.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/components/IconUploadField/IconUploadField.tsx, line 202:
<comment>When a project's accent color is ever malformed (not exactly `#rrggbb` — for example shorter `#fff` values that this same PR's ProjectThumbnail change explicitly protects against), picking a glyph bakes it through `hexToRgba`, which slices fixed offsets and yields `rgba(NaN,…)` channels, so the generated PNG won't carry the intended color. The renderer's thumbnail was just hardened for this exact case (treat malformed colors as unset), but the glyph-bake path here still trusts the raw value. Consider normalizing the color (fall back to `DEFAULT_GLYPH_COLOR` for anything that isn't a valid hex) before calling `glyphToDataUri`, mirroring the `isHexColor` guard added in ProjectThumbnail.</comment>
<file context>
@@ -186,20 +197,26 @@ export function IconUploadField({
+ let dataUri: string;
try {
- await setIcon(await glyphToDataUri(glyph, color));
+ dataUri = await glyphToDataUri(glyph, color);
} catch (err) {
toast.error(err instanceof Error ? err.message : "Could not set icon");
</file context>
| dataUri = await glyphToDataUri(glyph, color); | |
| const stroke = /^#[0-9a-fA-F]{6}$/.test(color ?? "") ? color : null; | |
| dataUri = await glyphToDataUri(glyph, stroke); |
…-icon-picker # Conflicts: # apps/desktop/src/renderer/routes/_authenticated/settings/v2-project/$projectId/components/V2ProjectSettings/V2ProjectSettings.tsx # packages/host-service/drizzle/meta/0015_snapshot.json # packages/host-service/drizzle/meta/_journal.json
…uping fixture Project rows gained a required `color` field in ParadevAI#6249; the fixture predates it and stopped compiling once main was merged in. Claude-Session: https://claude.ai/code/session_018Dar8wdxaut9yBU8NB7H4t
…uping fixture Project rows gained a required `color` field in ParadevAI#6249; the fixture predates it and stopped compiling once main was merged in.
* docs: weekly update for PRs merged 2026-08-05 to 2026-08-12 - workspaces: sessions (project-less workspaces, #6274), pin + drag-and-drop pinning (#6364), list/board views with Merged & Deleted history columns (#6296), per-project naming instructions (#6250), multi-PR links per branch with remove/restore (#5924) - automations: session automations (#6280), list health stats + Up next grouping + read-only team automations (#6291, #6276), detail page Settings/Run History tabs, inline run errors, would-run preview, RRule validation (#6305) - editor: image pane pan/pinch/zoom (#6285) - tasks: multi-repo filters, expanded task states, PR author/review filters, PR checks (#6201) - monorepos: per-project sparse checkout (#6034) - customization: project icon + color picker, v1 color carry-over (#6249) - terminal presets: built-in Superset CLI preset (#6270) - agents: resume interrupted sessions + Resume Args setting (#6253, #6265), Superset hooks toggle + scoping (#6072) - cli: interactive command browser + branded help (#6273); reference updated for session mode, --task, --skip-branch-prefix, --session (verified against packages/cli/src/commands) * docs: tighten wording and drop em dashes Shorten this week's additions per the writing guide: one thought per sentence, plainest word, no em dashes as prose punctuation. Also sweeps the three pre-existing em dashes in recipes. * docs: add screenshots from the 08-09 changelog batch cli command browser, agent resume banner, PR view with checks, and the project icon/color picker. Copied into apps/docs/public/images per the SOP rather than referenced across apps.
Links
Summary
color(new column +project.setColor), shown as the v1-style tinted border/letter on v2 project thumbnails in settings and the dashboard sidebar.Why / Context
Laurent's V2 feedback: color-coded project icons are how users orient across many projects, and V1 colors were lost on import. His third item — "Remove icon" throwing
No procedure found on path v2/project/removeIcon— was already fixed at the source by #5845 (the dead cloud icon machinery was deleted); no call sites remain and reset goes throughproject.setIcon(null). This PR covers the two remaining items.How It Works
projects.colorcolumn (drizzle-kit migration0015, applies on host boot), threaded throughProjectSnapshot,project.list/project.get, and theproject:changedevent. Newproject.setColormutation mirrorssetIcon(validates#rrggbb, null clears).useHostProjectsrows/merge and the dashboard sidebar tree carrycolor; older hosts and stale IndexedDB snapshots normalize tonull.IconUploadFieldbecomes a popover withColorSelectorswatches (extended with an opt-in Default option) and a lucide glyph grid. Glyphs are baked client-side into the same 128px PNG data-URI the upload path uses, so they flow throughresolveProjectIconUrland appear on every surface with zero resolver changes. Picking a color re-bakes a glyph chosen in the same popover session.importV1Projectbest-effort callssetColorafter a successful import; the v1"default"sentinel stays unset, and a failure logs without failing the import.Manual QA Checklist
Icon + color picker (v2 project settings)
V1 → V2 import
Migration safety
ALTER TABLE ... ADD color text)Testing
bun run typecheck— pass (all packages)bun run lint— cleanapps/desktopbun test— 2541 pass / 0 fail (includes new color carry-over test inrunV1Migration.test.ts)packages/host-servicebun test— 997 pass / 0 failDesign Decisions
setIcon,resolveProjectIconUrl, every thumbnail surface) with no resolver or protocol changes. Trade-off: a baked glyph can't re-tint retroactively, so only a glyph picked in the same popover session follows a color change.Known Limitations
setColor) surfaces "No procedure found" as a toast — same version-skew behavior as other new host procedures.Compatibility Matrix
colorfield in list/get/events is ignored.Summary by cubic
Add host-local project accent colors to v2 and let users remove the project icon. Ships an icon+color picker with tinted thumbnails/sidebar, carries v1 color and hide-image, and fixes picker edge cases (glyphs re-bake only after color saves, swatches disable while saving, strict #rrggbb parsing) (Linear SUPER-1779).
New Features
host-service: addprojects.colorandproject.setColor; thread through list/get/events.project.setIconnow accepts a"none"sentinel to force the letter tile (no avatar fallback).#rrggbbparsing avoids malformed tints.Migration
0016addsprojects.color(additive; applies on host boot).hide_imageto the"none"icon; the v1 "default" color sentinel stays unset; failures don’t block import.Written for commit 331bb71. Summary will update on new commits.
Summary by CodeRabbit