* feat: add configurable Open In menu
Implements configurable Open In applications in worktree context menus with persisted settings, preload/API wiring, and renderer controls/tests.\n\nDesign doc: docs/configurable-open-in-menu.md
* fix: address review findings
* feat: add crash report submission flow
* Capture crash-report breadcrumbs
- Add a memory-only crash breadcrumb ring buffer and persist snapshots only
when a crash report is recorded
- Include sanitized recent activity in crash diagnostics and tests
- Prevent dismissing or closing the crash dialog while submission is in flight
Co-authored-by: Orca <help@stably.ai>
* fix: address auto-review findings
* chore: remove crash report preview artifact
---------
Co-authored-by: Orca <help@stably.ai>
* fix: label macOS dev Dock instances
* fix: keep dev badge visible in Dock labels
* chore: clean up dev identity plumbing
* feat: add stable-name dev command
* feat(file-explorer): show gitignored files with dimmed italic decoration
Surfaces `.gitignore`d files in the right-sidebar file explorer with an
italicised, dimmed filename and a CircleSlash icon in the same trailing
slot used by the git status letter. A tracked change always wins — the
ignored decoration only applies when no other git status is present.
Gated behind a new `showGitIgnoredFiles` global setting (default on) so
heavy SSH workspaces can keep the smaller payload by skipping
`--ignored=matching` on `git status`.
`ignoredPaths` lives as a peer field on GitStatusResult rather than an
extension of GitFileStatus/GitStagingArea, so Source Control's
staging-area grouping is untouched.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(file-explorer): trim redundant comments from gitignored decoration
Removes duplicated "Why:" explanations that ended up restating the same
backward-compat rationale across five files (relay, ssh provider, runtime
git commands, RPC handler, renderer git client) plus a few comments that
narrated the mechanism the code already shows.
Net: -39 lines of comment across 10 files; no behavior change.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(file-explorer): drop remaining comments from gitignored decoration
The code reads well without them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* review: harden gitignored file decorations
- clear ignored decoration cache when ignored status is disabled or omitted
- keep ignored decoration state scoped across worktree and runtime cleanup
- add coverage for local, SSH, runtime, relay, and Explorer precedence
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Jinjing <6427696+AmethystLiang@users.noreply.github.com>
* Add worktree open-in editor button
Implements the Open in menu flow from docs/open-in-worktree-button.md, including shell IPC validation and sidebar menu integration.
* Move worktree open action into menu
Updates the design to remove the card button and show VS Code under a single Open in context-menu item.
* Shorten worktree file manager labels
* feat(gitlab): add foundational glab runner, types, and issue operations
First slice of GitLab support, mirroring src/main/github/ structurally
without refactoring the working GitHub path.
- runner: add glabExecFileAsync parallel to ghExecFileAsync (same WSL
routing and retry policy; HTTP-status / network classification is
provider-agnostic so the existing helpers are reused).
- types: GitLabProjectRef carries host alongside path so self-hosted
instances and nested groups round-trip through the IPC layer. Mirror
shapes for MR/issue/work-item/comment/file/assignable-user.
- gitlab/gl-utils: concurrency limiter, error classification, project-ref
resolution honoring upstream/origin preference, and known-host
discovery via `glab auth status` so non-gitlab.com remotes are
recognized after the user authenticates.
- gitlab/mappers: pipeline-job → check-status mapping, MR state
resolution (including draft inferred from `Draft:`/`WIP:` title
prefix), and pipeline rollup.
- gitlab/issues: full issue CRUD via `glab api` against URL-encoded
project paths, with the same upstream/origin preference semantics as
the GitHub side.
63 unit tests passing across gl-utils / mappers / issues. Both
typecheck:node and typecheck:web clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): preflight glab auth check and URL parser
- preflight: probe `glab --version` + `glab auth status` alongside the
existing gh checks. PreflightStatus.glab is optional so renderer call
sites that only render git/gh keep typechecking; consumers gating on
GitLab affordances opt in via `glab?.authenticated`.
- gitlab-links: parse GitLab issue and merge-request URLs honoring (a)
arbitrary self-hosted hosts via the project-internal `/-/` separator
rather than locking to gitlab.com, (b) nested group paths, and (c)
GitLab's `!42` MR convention alongside `#42`.
26 unit tests added (5 new preflight cases, 21 URL-parser cases). Full
typecheck (node + cli + web) clean. Pre-existing runtime/orchestration
test failures unrelated to this branch — Node 25 vs the project's
pinned Node 24 engine.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): MR list/get + paginated `glab api -i` helper
Lean mirror of github/client.ts focused on the workspace-from-MR
keystone. Adopts GitLab-native filter semantics (Open / Merged /
Closed / All) instead of porting GitHub's search-DSL — that path is
covered by the upcoming My Todos surface.
- gl-utils: glabApiWithHeaders + parseGlabApiResponse for strict
pagination via X-Total / X-Total-Pages on `glab api -i` output.
CRLF / LF tolerant; status line never leaks into the headers map.
- types: MRListState, GitLabPagedResult<T>, ListMergeRequestsResult.
- mappers: mapMRToWorkItem + mapIssueToWorkItem produce the unified
GitLabWorkItem shape the picker consumes. isCrossRepository derived
from source_project_id !== target_project_id; deterministic id
fallback when the per-MR detail endpoint omits global id.
- client: getAuthenticatedViewer, getMergeRequest (with head pipeline
rolled up), getMergeRequestForBranch (mirrors github/getPRForBranch
semantics including refs/heads/ stripping and detached-HEAD guard),
listMergeRequests (paginated), getWorkItemByProjectRef (paste-URL
flow). Re-exports issues + projectRef helpers so callers don't have
to know the gl-utils module split.
35 new tests (98 total in src/main/gitlab/), full typecheck clean.
Tests split into client.test.ts + client-mr.test.ts to stay under the
oxlint max-lines budget — matches github/client*.test.ts pattern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): worktrees:resolveMrBase IPC + linkedGitLab* persistence
The workspace-from-MR keystone. Mirror of worktrees:resolvePrBase
shape and semantics — caller passes mrIid (with optional source_branch
/ isCrossRepository hints), handler returns either a remote/branch
ref (same-project MRs) or a SHA fetched from
refs/merge-requests/<iid>/head (fork MRs).
- types: linkedGitLabMR / linkedGitLabIssue on Worktree + WorktreeMeta.
Marked optional so existing test fixtures and persisted older
worktrees that pre-date these fields keep typechecking and loading
without a migration.
- persistence: getDefaultWorktreeMeta initializes both fields to null.
- worktree-logic: mergeWorktree carries them through from meta.
- worktrees IPC: resolveMrBase mirrors resolvePrBase. Resolves the
GitLab project via getProjectRef + known-host discovery, fetches the
MR work-item to derive source_branch + isCrossRepository when those
hints aren't provided, and uses GitLab's refs/merge-requests/<iid>/head
for fork MRs (parallel of GitHub's refs/pull/<N>/head).
- tests: 6 fixture updates for the new optional fields. Full
typecheck (node + cli + web) clean; 165 tests passing across
src/main/gitlab/, preflight, worktree-logic, and gitlab-links.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): IPC channels + preload bindings (gl.*)
Wire the GitLab backend to the renderer. Lean v1 surface — issues
CRUD, MR list/get/getForBranch, viewer, project slug, paste-URL
work-item lookup. Skips workItemDetails / listWorkItems-combined /
listTodos until the matching backend pieces land.
- main/ipc/gitlab.ts: thirteen handlers under the `gitlab:*` channel
prefix with the same assertRegisteredRepo guard the gh handlers use.
listIssues unwraps the structured result envelope to bare items[]
to match window.api.gh.listIssues' shape; consumers that need the
classified error can graduate to the envelope later.
- main/ipc/register-core-handlers.ts: register alongside gh.
- preload/api-types.ts: typed `gl: { ... }` block parallel to the
existing `gh: { ... }`. Imports the new GitLab types so renderer
code consuming the preload gets full inference.
- preload/index.ts: runtime `gl: { ... }` exposes wired to ipcRenderer.
Full typecheck (node + cli + web) clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): workspace-from-MR via paste-URL (keystone end-to-end)
The first user-visible GitLab moment. Pasting a GitLab issue or MR URL
into the workspace name field now resolves through the full pipeline
to a created workspace with the right base ref and linkedGitLab*
persisted. The dedicated GitLab tab + state-filter chips remain a
follow-up; everything below it is wired.
- shared/lib/new-workspace.ts: LinkedWorkItemSummary.type accepts
`'mr'` alongside `'issue' | 'pr'`. Renderer code that switches on
type explicitly handles each kind.
- ui store slice: NewWorkspaceDraft mirrors the new linked slots so
drafts persist GitLab selections across navigation. Optional fields
for backward compatibility with drafts saved before this branch.
- useComposerState:
- linkedGitLabIssue / linkedGitLabMR state, draft persistence,
repo-switch reset, applyWorktreeMeta wiring.
- applyLinkedGitLabWorkItem mirrors applyLinkedWorkItem; reuses
getLinkedWorkItemSuggestedName by structurally projecting the
GitLab item onto the helper's input shape.
- handleSmartGitLabItemSelect parallels handleSmartGitHubItemSelect:
for picked MRs, calls window.api.worktrees.resolveMrBase to
resolve the base ref (refs/merge-requests/<iid>/head for fork
MRs) and threads it through handleBaseBranchMrSelect.
- "was MR !N" reset hint when a repo switch wipes a GitLab
selection — `!N` matches gitlab.com's MR-reference convention.
- preload: window.api.worktrees.resolveMrBase + window.api.gl.* are
already in. ComposerCardProps grows onSmartGitLabItemSelect (+
optional onBaseBranchMrSelect).
- SmartWorkspaceNameField:
- Paste-URL detection: parseGitLabIssueOrMRLink (host-agnostic via
`/-/` separator) → window.api.gl.workItemByPath → row in the
dropdown → click → forwarded to onGitLabItemSelect.
- SmartWorkspaceNameSelection union, RowEntry union, RowIcon,
RowLabel, SelectionIcon all carry the gitlab-mr / gitlab-issue
kinds. MR rows show `!N` prefix; issue rows show `#N`.
- Tab UI not added in this commit — paste-URL works in 'smart'
mode, the dedicated tab + Open/Merged/Closed/All chips lands
in a follow-up.
- NewWorkspaceComposerCard: forwards onSmartGitLabItemSelect to the
picker.
Full typecheck (node + cli + web) clean. 165 unit tests passing in
affected files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): GitLab tab in SmartWorkspaceNameField with state filter
The discoverable demo path. The picker now has a "GitLab" tab — when
selected it lists the project's MRs filtered by state via
`gitlab:listMRs`, with an Open / Merged / Closed / All chip strip
that mirrors gitlab.com's MR-page tab strip. Paste-URL detection in
'smart' mode is unchanged; the new tab simply makes the surface
discoverable without requiring a URL.
- SmartNameMode gains 'gitlab'; Gitlab icon (lucide) added to the
MODES array between GitHub and Branch.
- MrStateFilter / MR_STATE_FILTERS centralizes the four chip values
so the labels stay GitLab-native (Open vs the GraphQL 'opened').
- listMRs effect: fires when mode === 'gitlab' and no GitLab URL is
in the input, with the current state filter and a page-1 fetch
bounded by RESULT_LIMIT.
- Paste-URL effect now coexists with the list effect: it owns
gitlabItems while a URL is in the input, the list effect owns it
otherwise. Switching tabs no longer clears the list.
- Chip strip rendered above the popover's CommandList only when
mode === 'gitlab'. Buttons use the same Button component the rest
of the picker uses for visual consistency.
Full typecheck (node + cli + web) clean. 165 unit tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): GitLab source on Tasks screen
The Tasks screen now offers GitLab as a third source alongside GitHub
and Linear. Selecting it surfaces MRs and issues for the primary
selected repo with a state filter (Open / Merged / Closed / All) that
mirrors gitlab.com's MR-page tab strip. Skips cross-repo aggregation,
search DSL, and Projects mode for v1 — those layers are GitHub-API-
shaped and would need a parallel store slice that is not worth porting
ahead of the actual demand for them.
- shared/types: GlobalSettings.defaultTaskSource accepts 'gitlab'.
- TaskPage:
- TaskSource union grows a 'gitlab' member; SOURCE_OPTIONS adds the
Gitlab icon between GitHub and Linear so the toolbar order matches
SmartWorkspaceNameField for cross-surface consistency.
- GITLAB_TASK_FILTERS centralizes the four chip values.
- Per-source state slim (matches Linear's pattern) — gitlabFilter,
gitlabItems, gitlabLoading, gitlabError, gitlabRefreshNonce.
- Data-fetch effect runs Promise.all over `window.api.gl.listMRs`
and `window.api.gl.listIssues` for the primary repo, merges and
sorts by updatedAt desc. 'merged' filter skips the issue fetch
(GitLab issues are 'opened' / 'closed' only).
- Filter bar block parallel to Linear's, with chips + a refresh
icon-button.
- List block: 5-column grid (ID / Title / Type+State / Updated /
Open-link). Row click opens the web URL — the GitLabItemDialog
is a follow-up commit, but the row affordance is enough for the
Tasks-screen demo.
- GitLab MRs render as `!N`; issues render as `#N` to match
gitlab.com's reference convention.
Full typecheck (node + cli + web) clean. 165 unit tests still
passing in affected files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): GitLabItemDialog (minimal) + Tasks screen wiring
Clicking a GitLab row on the Tasks screen now opens a side-sheet
preview with the item's title, state, author, and description body
rendered as markdown. "Open in browser" footer button stays as the
escape hatch; opening from the row is dialog-first now (matching the
GitHub side's row-click-to-dialog pattern). Files / comments /
pipeline tabs are deferred — they mirror substantial GitHub-side
surface area (work-item-details ~550 lines, GitHubItemDialog 2680
lines) and are not blocking the demo.
- types: MRInfo and GitLabIssueInfo gain optional description /
author / authorAvatarUrl. Optional because list endpoints strip
them; populated on detail-endpoint reads (`getMR` / `getIssue`).
- mappers: mapMRInfo and mapGitLabIssueInfo now pass description /
author / avatar through when present. Skipped (rather than
defaulted to '') so callers can distinguish "no body authored"
from "this came from a list".
- GitLabItemDialog: new ~200-line side sheet. Fetches the detail
payload via `window.api.gl.mr` / `gl.issue` on open; renders
CommentMarkdown for the description (reused from the GitHub
side); falls back to "No description." when the body is blank.
State badge tones picked locally — GitLab's MR state space is
wider than GitHub's so coupling them buys nothing.
- TaskPage: GitLab row now uses a div role=button with keyboard
handling so the inner Open-in-browser <button> nests cleanly
(HTML disallows nested <button>s, React would warn). Row click
sets gitlabDialogItem; the small ExternalLink icon stops
propagation so it still opens the URL.
Full typecheck (node + cli + web) clean. 165 unit tests passing in
affected files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): My Todos cross-project view on Tasks screen
The GitLab tab now has a Project | My Todos sub-toggle. "My Todos"
fetches gitlab.com/dashboard/todos via `glab api todos?state=pending`
and surfaces them in a separate table — action / title / project /
updated. This is the closest GitLab-native equivalent of GitHub's
notifications/inbox and lands in lieu of porting GitHub's search-DSL
which doesn't translate.
- shared/types: GitLabTodo type with action_name, target_type/iid,
target_url, project_path, author, updated_at. action_name kept as
open-ended string because new GitLab versions extend the verb set.
- gitlab/client.ts: listTodos uses `glab api --paginate todos?state=
pending&per_page=50`. User-scoped — cwd doesn't matter, but the
IPC path-validation guard still requires *some* registered repo
path so we keep the signature consistent with the rest of gl.*.
- IPC: `gitlab:todos` channel; preload `gl.todos`.
- TaskPage:
- gitlabView ('project' | 'todos') gates which list to render.
- Sub-toggle row above the chip strip; chips are hidden on the
Todos view since pending state has no Open/Merged/Closed axis.
- Refresh button serves both views (uses gitlabRefreshNonce).
- Todos table: 5-col grid, action verb (snake_case → spaces),
target title, project path (mono font for repo-likeness),
updated date, open-link icon. Row click opens target_url.
Full typecheck (node + cli + web) clean. 165 unit tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): gitlabProjects settings (recents auto-tracked) + tests
Settings persistence for GitLab project preferences plus tests for
the surface added since the last green run.
- shared/types: GitLabProjectSettings { pinned, recent } and an
optional GlobalSettings.gitlabProjects slot. Optional for
backward compat with profiles saved before this branch — the
persistence merge fills the empty default.
- shared/gitlab-projects: pure helper computeNextGitLabRecents that
prepends-and-dedupes by host+path, caps at GITLAB_RECENTS_MAX
(10). Pulled out of the IPC handler so it tests without mocking
Store.
- gitlab IPC: workItemByPath handler now pushes the resolved
project ref onto recents on success. 404 / auth-fail lookups
do not pollute the list — recents reflects projects the user
actually read.
Tests added (12 new, 177 total passing in affected files):
- gitlab-projects.test: prepend, dedupe, host-vs-host distinct,
cap at max, no input mutation.
- client.test: listTodos mapping, defensive state coercion,
empty-on-error fallback, missing-target field defaults.
- mappers.test: description / author / authorAvatarUrl pass-
through on both mapMRInfo and mapGitLabIssueInfo, plus the
"absent vs blank" distinguishing assertion.
- mappers-workitem.test (split): mapMRToWorkItem + mapIssueToWorkItem
cases moved out of mappers.test.ts to keep both files under the
oxlint max-lines budget.
Full typecheck (node + cli + web) clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): combined listWorkItems IPC + TaskPage refactor
Centralize the MR + issue merge logic that TaskPage was doing inline
into a single backend function and IPC channel. Future callers (the
picker's GitLab tab, any new widget) get the merge / sort / state-
mapping rule for free. The TaskPage effect drops from 60 lines of
inline orchestration to a single call.
- gitlab/issues: listIssues now accepts an IssueListState so the
combined caller can ask for closed / all instead of always opened.
CLI fallback path picks the right --opened / --closed / --all flag
per glab version. Existing callers keep the 'opened' default.
- gitlab/client: listWorkItems(state, page, perPage, preference) fans
out listMergeRequests + a raw issues fetch in parallel, merges by
updatedAt desc, returns a GitLabPagedResult<GitLabWorkItem>.
Bypasses listIssues for the issues side because IssueInfo strips
updated_at — the combined sort needs it.
state='merged' skips the issues fetch entirely (issues don't have
a merged lifecycle).
- IPC: new gitlab:listWorkItems handler.
- preload: gl.listWorkItems alongside gl.listMRs.
- TaskPage: GitLab fetch effect now calls gl.listWorkItems and stops
re-implementing the merge. Same UX, fewer moving parts.
Tests added (8 new in client-work-items.test.ts; +1 fix to
issues.test.ts for the new url-param order):
- merge ordering by updatedAt desc
- 'merged' state skips issues fetch
- closed / all state pass-through
- not_found envelope when project ref unresolved
- mr-error vs issue-side success interleaving
- combined error surfacing on either side failing
Full typecheck (node + cli + web) clean. 117 unit tests passing in
src/main/gitlab/ and src/shared/gitlab-projects.test.ts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): work-item-details + dialog Conversation/Pipeline tabs
Task 3 lean version. The minimal description-only dialog grows two
new tabs (Conversation / Pipeline) and four footer actions
(close / reopen / merge / comment). Files-tab and inline review-
comment positioning stay deferred — they mirror substantial GitHub-
side surface (GitHubItemDialog is 2680 lines, work-item-details.ts is
551) and the v1 demo doesn't need them.
- shared/types: GitLabPipelineJob (id, name, stage, status, webUrl,
duration), GitLabWorkItemDetails (item + body + comments[] +
pipelineJobs?[]). Mirrors GitHubWorkItemDetails layout.
- main/gitlab/work-item-details: getWorkItemDetails(repoPath, iid,
type) fans out parallel reads — issue: detail + discussions; MR:
detail + discussions, then pipeline jobs follow-up keyed off
head_pipeline.id. Discussion → MRComment flatten skips system
notes (auto-generated activity entries) so the conversation tab
shows only user content. Inline-review position carried through
as `path` + `line` for v1.5 to consume.
- main/gitlab/client: closeMR / reopenMR / mergeMR / addMRComment
mutations. mergeMR accepts the same 'merge' | 'squash' | 'rebase'
union as the GitHub side; close/reopen treat "already X" stderr
as success since the desired state is reached.
- IPC: gitlab:workItemDetails, closeMR, reopenMR, mergeMR,
addMRComment channels; preload `gl.*` bindings parallel.
- GitLabItemDialog rewrite: three Tabs (Description / Conversation /
Pipeline-MRs-only) + footer with comment composer + state-aware
Merge / Close / Reopen buttons. Cmd/Ctrl+Enter sends the comment
to match gitlab.com's textarea shortcut. Refresh icon in the
header re-fetches via a refreshNonce. eslint-disable max-lines on
the dialog matches the GitHub-side equivalent's reasoning.
Full typecheck (node + cli + web) clean. 184 unit tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): sidebar icon, Smart-mix MRs, Integrations card, "Project MRs" rename
Four follow-up fixes that surfaced from smoke-testing:
- SidebarNav: GitLab icon next to GitHub / Linear in the Tasks-row
shortcut strip; clicks open the Tasks page already filtered to the
GitLab source. ui.ts taskPageData.taskSource union grows to accept
'gitlab' so the openTaskPage call typechecks.
- SmartWorkspaceNameField: list-MRs effect now fires in 'smart' mode
too, not just on the dedicated GitLab tab. The mixed picker
surfaces the user's project MRs alongside GitHub items. Paste-URL
effect still wins when a GitLab URL is in the input — the list
effect bails on parsedGlLink !== null.
- TaskPage: GitLab toggle relabels "Project" → "Project MRs" so the
pairing with "My Todos" reads more clearly.
- IntegrationsPane: new GitLab card mirroring the GitHub card —
status badge (checking / connected / not-installed / not-
authenticated), install link to gitlab.com/gitlab-org/cli, copy-
ready `glab auth login` block, learn-more link to the auth/login
doc, re-check button. Search-entry registered so settings search
finds it. eslint-disable max-lines justified by the same pattern
that already lives there for GitHub + Linear.
- preload: PreflightStatus.glab is optional on the type so older
payloads typecheck; consumers gate on the optional chain.
Full typecheck (node + cli + web) clean. 184 unit tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(gitlab): multi-repo aggregation on Tasks screen
Mirrors GitHub's cross-repo behavior. Previously the GitLab tab only
queried the first selected repo; now it fans out to every eligible
selected repo in parallel and merges results sorted by updatedAt
desc. The repo selector at the top of Tasks is the project picker —
it's the same one the GitHub tab uses, so the selection model is
consistent across providers.
- TaskPage gitlab fetch effect: Promise.allSettled across all
selectedRepos that aren't SSH-relay (folder-mode repos and remote
worktrees fall through). Each repo's project is resolved from its
own git remote by the main process; non-GitLab repos return
not_found which the renderer drops silently so a mixed selection
(GitHub + GitLab repos) doesn't surface false errors on the GitLab
tab.
- Per-row repoId tagging stays correct — items keep their source
repo's id through the merge, which matters for the dialog repoPath
resolution below.
- Banner display: only shown when EVERY eligible repo failed; partial
failure is signaled by the row count being lower, not a banner that
overshadows working repos.
- GitLabItemDialog repoPath: derived from the clicked item's
source repo (selectedRepos.find by repoId) instead of primaryRepo.
Without this, clicking an item from a non-primary repo would route
the detail fetch through the wrong repo's remote.
Full typecheck (node + cli + web) clean. 117 unit tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(gitlab): swap MR icon to GitMerge for visual distinction
GitPullRequest (curved-merge) reads similar to GitBranch (forking
line) at the small sizes we use in the picker — feedback was that
MR rows looked like branch rows. GitMerge (arrow-merge-into-line)
reads as its own thing and matches gitlab.com's MR iconography, so
users coming from the web UI find it familiar.
GitHub PRs keep GitPullRequest — that matches github.com and keeps
provider attribution distinct from GitLab MRs at a glance:
GitHub PR: GitPullRequest (curved merge)
GitLab MR: GitMerge (arrow merge)
Branch: GitBranch (fork)
Issue: CircleDot (provider-agnostic)
- SmartWorkspaceNameField RowIcon + SelectionIcon: gitlab-mr →
GitMerge. github-pr stays GitPullRequest.
- GitLabItemDialog header icon: GitMerge for MRs.
Full typecheck (node + cli + web) clean. 117 unit tests passing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* refactor(gitlab): split shared types + preload into per-provider files
Pre-emptive merge-conflict reduction. The two recent main syncs
each surfaced ~5 conflicts, all in the same handful of central
files where every provider lands code. Moving the GitLab footprint
into provider-scoped files cuts the conflict surface roughly in half
without changing any runtime behavior.
- shared/gitlab-types.ts (new, 272 lines): every standalone GitLab
type that previously lived in shared/types.ts —
GitLabProjectRef / MRState / MRMergeableState / MRCheckDetail /
MRInfo / GitLabReaction / MRComment / GitLabCommentResult /
GitLabIssueInfo / GitLabViewer / GitLabAssignableUser /
GitLabWorkItem / GitLabMRFile / GitLabProjectSettings /
GitLabTodo[TargetType] / GitLabPipelineJob /
GitLabWorkItemDetails / GitLabIssueUpdate / MRListState /
GitLabPagedResult / ListMergeRequestsResult.
- shared/types.ts: re-exports the GitLab types so existing call
sites importing from '../shared/types' keep working unchanged.
GitLabProjectSettings additionally imported locally for the
GlobalSettings.gitlabProjects field. Worktree.linkedGitLabMR /
WorktreeMeta.linkedGitLabIssue / GlobalSettings.defaultTaskSource
union member stay here — they're entangled with non-GitLab
structs and moving them out would just shuffle the conflict
vector to a different file.
- preload/gitlab.ts (new, 106 lines): the entire gl.* runtime
binding block — viewer / projectSlug / mrForBranch / mr /
listMRs / listWorkItems / issue / listIssues / createIssue /
updateIssue / addIssueComment / listLabels /
listAssignableUsers / todos / workItemDetails / closeMR /
reopenMR / mergeMR / addMRComment / workItemByPath. Exported as
`glApi`.
- preload/index.ts: imports `glApi` and inlines as `gl: glApi`,
shrinking the file by ~95 lines.
Net: the two files most prone to conflict on upstream sync
(shared/types.ts, preload/index.ts) lose ~360 lines of
GitLab-specific code that now live in their own files where main's
non-GitLab edits can't touch them.
Full typecheck (node + cli + web) clean. 190 unit tests passing
in src/main/gitlab/, src/shared/gitlab-projects.test.ts,
src/main/ipc/{preflight,worktree-logic}.test.ts,
src/renderer/src/lib/gitlab-links.test.ts.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(gitlab): satisfy pnpm pre-flight (lint + handler-registration test)
- TaskPage: lift the selected-repos identity key into a useMemo so the
GitLab fetch effect's dep array no longer holds a complex expression
(oxlint exhaustive-deps).
- register-core-handlers.test: mock ./gitlab alongside ./github / ./linear
so registerGitLabHandlers doesn't try to call ipcMain.handle in a unit
test that fakes only individual handler modules.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* feat(source-control): add Bitbucket hosted review support
* fix(source-control): align hosted review lookup with provider model
---------
Co-authored-by: Emilian Stoilkov <emilian.stoilkov@qaiware.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>