feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat(sidebar): configurable project grouping (port upstream #2055) - #49

Merged
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping
Apr 21, 2026
Merged

feat(sidebar): configurable project grouping (port upstream #2055)#49
tyulyukov merged 5 commits into
mainfrom
marcode/port-configurable-project-grouping

Conversation

@tyulyukov

Copy link
Copy Markdown
Owner

Summary

  • Port upstream feat: configurable project grouping pingdotgg/t3code#2055: adds configurable project grouping modes to the sidebar
    • repository: Group all projects from the same git repository together
    • repository_path: Group only when both repository and repo-relative path match (default)
    • separate: Keep every project path as its own sidebar row
    • Per-project overrides allow fine-grained control over grouping behavior
  • Add projectPaths utility module with path normalization helpers (prerequisite)
  • Extend RepositoryIdentityResolver to track git root paths for each project
  • Support context menu submenus in desktop app for multi-member project actions (rename, grouping, delete)
  • Add UI dialogs for renaming projects and managing grouping overrides
  • Map Claude SDK effort level xhighmax (SDK compatibility fix)

Testing

  • Unit tests cover path normalization, logical project key derivation, and grouping snapshots
  • Nested workspace resolution tested—correctly resolves to git root from subdirectories
  • Sidebar grouping logic tested with mixed environments and multiple grouping modes
  • Desktop context menu recursion tested with nested submenu structure
  • Browser integration test verifies logical project key persistence across UI state
  • All existing tests updated to use logical project keys

tyulyukovand others added 2 commits April 21, 2026 01:36
…ing)
Extracts normalizeProjectPathForComparison and path regex helpers from
upstream pingdotgg#2024 in isolation, so they're available as a dependency for
the configurable project grouping port (pingdotgg#2055). Adds @marcode/shared/path
subpath export.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…#2055)
Port upstream t3code pingdotgg#2055 (188a40c) to add three sidebar project
grouping modes (repository, repository_path, separate) plus per-project
overrides via nested context-menu submenus.
MarCode reconciliation:
- Preserved skeleton loading (SidebarProjectsSkeleton) in Sidebar.tsx
- Preserved cross-environment thread fetching via memberProjectRefs
- Kept ThreadStatusIndicators import (from pingdotgg#2107 GitLab MR port)
- Kept Opus 4.7 default effort = "high" in ClaudeProvider
- Kept turn notification wiring, Jira embedded defaults, windowState
persistence, custom draft-thread system in ChatView
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tyulyukovand others added 3 commits April 21, 2026 13:50
…le settings
readClientSettings() loads client-settings.json as a raw JSON blob without
running the schema decoder, so users with pre-upgrade settings files have no
sidebarProjectGroupingOverrides key. Dereferencing it with bracket access
threw "Cannot read properties of undefined (reading '\${envId}:\${path}')"
and blocked the app from opening.
- resolveProjectGroupingMode: optional-chain the overrides record and fall
back to DEFAULT_SIDEBAR_PROJECT_GROUPING_MODE when the mode itself is
missing
- openProjectGroupingDialog: optional-chain the overrides lookup
- Grouping-rule Select "global default" label falls back to the default
mode when settings.sidebarProjectGroupingMode is missing
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ttings
Forks with both origin and upstream were surfacing the upstream repo name
because pickPrimaryRemote prioritized upstream. Flip the order so a user's
own fork wins, making the canonicalKey consistent with their working tree.
Client settings hydration replaced the default snapshot with raw persisted
JSON, so fields added in later versions (e.g. sidebarProjectGroupingMode)
stayed undefined on upgrade. Deep-merge with DEFAULT_CLIENT_SETTINGS so
missing keys inherit defaults.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Pre-existing projects never got grouped in the sidebar because
getListingSnapshot (the Phase 1 bootstrap used to paint the sidebar)
omitted repositoryIdentity. New projects happened to work because
project.created events carry the resolved identity, but rows read at
startup only had whatever the listing snapshot populated — which was
nothing. Mirror the resolver call from getSnapshot so every listed
project has identity and logical-project grouping can key off it.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@tyulyukov
tyulyukov merged commit fbbfa24 into mainApr 21, 2026
4 of 5 checks passed
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@tyulyukov@tlh38