5.6 KiB
Commit Failure Summary
Problem
In Source Control, commit failures are stored per worktree in commitErrors (Record<string, string | null>) and rendered inline by CommitArea as raw text (src/renderer/src/components/right-sidebar/SourceControl.tsx, handleCommit and commit-area-error).
git.commit failures can include full hook/lint output (multi-line, ANSI-colored, very long). Rendering raw output inline expands the sidebar and pushes core controls out of view.
Goal
Show a short inline failure summary while keeping the full raw error available in a modal dialog.
Non-goals
- No IPC/runtime/provider contract changes (
git.commitstays{ success, error? }). - No exhaustive parser for every hook/linter format.
- No changes to remote-action errors or AI commit-generation errors.
Constraints from current code
handleCommitalready stores raw commit error per worktree and clears it at commit start/success.CommitAreacurrently renderscommitErrorverbatim in#commit-area-errorwithrole="alert"andaria-live="polite".commitError,remoteActionError, andgenerateErrorare independent and all can be referenced by textareaaria-describedby.- Worktree-local state is intentionally preserved across worktree switches; stale keys are pruned when worktrees disappear.
Design
-
Add
src/renderer/src/components/right-sidebar/commit-failure-summary.ts:summarizeCommitFailure(raw: string): stringhasExpandedCommitFailureDetails(raw: string, summary: string): boolean
-
Keep parser scope strict and deterministic:
- Strip ANSI/control sequences and trim whitespace.
- Split to non-empty lines and ignore low-signal noise (for example npm env-replacement warnings) only when stronger failure lines exist.
- Detect common commit-hook/lint failures (
pre-commit,husky,lint-staged,eslint,oxlint, genericlint/Found N errors). - Return
Lint failed during commit.for clear lint/hook lint failures. - Return
Pre-commit hook failed.for hook failures without a clearer lint signal. - Otherwise return the first meaningful line.
- Empty input fallback:
Commit failed.
-
Render behavior in
CommitArea:- Replace inline raw error block with compact alert row using
TriangleAlert, summary text, and optionalDetailsbutton. - Preserve
id="commit-area-error",role="alert",aria-live="polite"for accessibility continuity. - Keep summary single-line/truncated to avoid sidebar growth.
- Replace inline raw error block with compact alert row using
-
Details dialog:
- Use existing
Dialogprimitive fromsrc/renderer/src/components/ui/dialog.tsx. - Title:
Commit Failed. - Description: summary.
- Body: scrollable
<pre>with raw error (whitespace-pre-wrap, mono styling, bounded height). - Footer close button via existing
DialogFooter/DialogClosepatterns. - Dialog open state is local to
CommitAreaand auto-resets closed when the active worktree changes orcommitErrorchanges/clears. - Reset key should include both worktree identity and error identity (for example
${worktreeId}:${commitError}), not only error text.
- Use existing
-
Derivation and state rules:
- Do not add new persisted error state in
SourceControl; derive summary/details from currentcommitErroronly. - Compute summary with
useMemokeyed bycommitErrorfor stable render behavior. - Keep raw error as source of truth; summary/details-visibility are derived every render.
- If hooks are introduced inside
CommitArea(dialog open state, memoized summary), update tests to render through React (<CommitArea {...props} />) instead of direct function invocation (CommitArea(props)), because direct invocation cannot run hookful components.
- Do not add new persisted error state in
Edge cases
- ANSI escape sequences in hook output.
- Errors emitted on either stderr or stdout (already possible in
commitChanges). - One-line failures: no
Detailsbutton when normalized raw text is effectively the same as summary. - Very large error payloads: inline remains bounded; full text stays dialog-only.
- Worktree switch while dialog open: details must reflect active worktree error; close dialog when error identity changes.
- Concurrent commit attempts:
- same worktree is already guarded (
commitInFlightRef). - different windows/processes can still mutate repo externally; UI must treat summaries as best-effort snapshots and refresh on next commit/status cycle.
- same worktree is already guarded (
Feasibility
- All work is renderer-only and compatible with current API boundaries.
- String normalization/parsing is cheap relative to render cost; no runtime or IPC latency impact.
- Existing dialog/button primitives cover required UX; no new UI infrastructure needed.
Tests
-
New unit tests for formatter module:
- lint-staged/husky/oxlint sample collapses to
Lint failed during commit. - pre-commit non-lint sample collapses to
Pre-commit hook failed. - generic non-hook error falls back to first meaningful line.
- ANSI stripping and empty-input fallback.
- details visibility predicate correctness.
- lint-staged/husky/oxlint sample collapses to
-
Update
CommitAreatests:- inline shows summary, not raw multiline payload.
- details trigger appears only when expanded details exist.
commit-area-errora11y attributes remain present.- dialog closes when
commitErrorclears/changes. - tests render
CommitAreaas a React component (not direct function call) once hooks are added.
-
Keep existing generate/remote error behavior unchanged (regression check).
Rollout
- Add formatter + tests.
- Integrate summary row + details dialog in
CommitArea. - Update commit-area tests.
- Run focused tests (
CommitArea*, formatter tests), thenpnpm typecheckandpnpm lint.