perf: stability and performance improvements with some minor UI issues resolved (#172)

* Stability and performance improvements. (#1)

## Changelog

### Performance Improvements

- **perf: make terminal creation cwd check async (#9)**  
  Replaced synchronous `fs.existsSync` with `fs.promises.access` in the terminal creation handler to prevent blocking the event loop.  
  Improves throughput under high load.

- **perf: optimize fuzzyMatchScore by avoiding redundant lowercasing (#8)**  
  Renamed `fuzzyMatchScore` to `fuzzyMatchScoreNormalized` and updated it to accept a pre-lowercased query, avoiding repeated string allocations.  
  Updated the call site in `searchFilesystemFiles`.  
  ~25% search performance improvement on large datasets.

- **perf: use async file read in update-install handler (#7)**  
  Replaced `fs.readFileSync` with `await fs.promises.readFile` to avoid blocking the event loop.  

  **Benchmark (10k ops):**
  - Sync: ~95ms (blocking)  
  - Async: ~1124ms (non-blocking)  

  Higher per-call overhead, but better server responsiveness.

- **perf(server): optimize mkdir endpoint with async fs (#6)**  
  Replaced `fs.mkdirSync` with `await fsPromises.mkdir` in `/api/fs/mkdir`.  
  Prevents event-loop blocking and improves concurrent performance.  

  **Result:** ~2× throughput improvement (100 concurrent requests).

- **perf: parallelize fs checks in validateProjectEntries (#4)**  
  Replaced serial `for...of` with `Promise.all + map`.  
  Reduced validation time for 500 projects from ~110ms to ~20ms (~5× speedup).

- **perf: cache getLoginShellPath result to avoid blocking event loop (#5)**  
  Cached `getLoginShellPath` result to avoid repeated `spawnSync` calls (~400ms each).  
  Subsequent calls reduced to <1ms.

---

### Server Fixes

- **fix(server): use async check for terminal restart endpoint (#3)**  
  Replaced `fs.existsSync` with `fs.promises.stat` in `/api/terminal/:sessionId/restart`.  
  Added directory validation for better robustness.

---

### UI & Accessibility

- **feat(ui): add aria-labels to git identities sidebar buttons (#1)**  
  - Added `aria-label="Create new profile"` to the create button  
  - Added `aria-label="Profile actions"` to the dropdown trigger  
  - Added `.Jules/palette.md` for UX/a11y learnings

---

### UI Performance (Bolt)

- ** Bolt: Optimize MessageList re-renders by preserving referential equality (#2)**
- ** Bolt: Optimize MessageList re-renders by preserving referential equality (#11)**
- ** Bolt: Optimize MessageList re-renders by preserving referential equality (#12)**

* stability and improvements (#17)

* feat: add corner radius setting and update snackbar actions

- Add `cornerRadius` to UI store and settings.
- Add Corner Radius slider to Visual Settings section.
- Apply corner radius to ChatInput component.
- Remove default close button from Snackbar (Sonner).
- Add "OK" action button to session deletion toasts.
- Ensure `cornerRadius` setting is visible in OpenChamberPage.

* fix(ui): add missing aria-label to radius slider and verify functionality

- Added `aria-label="Corner radius in pixels"` to the desktop version of the corner radius slider for accessibility.
- Verified functionality and accessibility compliance via script.

* fix(ui): restore input bar offset setting on desktop

- Restored the Input Bar Offset setting to be visible on desktop, not just mobile.
- Verified both Corner Radius and Input Bar Offset sliders are accessible.

* Fix mobile layout for chat input controls (#16)

* Fix mobile layout for chat input controls

- Reduced horizontal gaps in mobile model controls.
- Added max-width constraints to model, variant, and agent labels on mobile to prevent overflow and cramping.
- Optimized spacing for mobile view.

* feat(git): auto-select gitmoji for generated commit messages

When the "Generate commit message" feature is used and gitmoji is enabled, automatically prepend the appropriate gitmoji based on the commit subject keywords.

- Added `KEYWORD_MAP` to map commit types to gitmojis.
- Added `matchGitmojiFromSubject` helper.
- Updated `handleGenerateCommitMessage` to apply the gitmoji.

* feat(git): auto-select gitmoji for generated commit messages

- Added `KEYWORD_MAP` to map commit types to gitmojis.
- Added `matchGitmojiFromSubject` helper.
- Updated `handleGenerateCommitMessage` to apply the gitmoji.
- Fixed mobile layout for model controls.
This commit is contained in:
Ashik Ahmed
2026-01-18 14:28:49 +02:00
committed by GitHub
parent 8879573def
commit 934df2b7e6
13 changed files with 335 additions and 69 deletions
+78 -2
View File
@@ -67,6 +67,46 @@ const GITMOJI_CACHE_VERSION = '1';
const GITMOJI_SOURCE_URL =
'https://raw.githubusercontent.com/carloscuesta/gitmoji/master/packages/gitmojis/src/gitmojis.json';
const KEYWORD_MAP: Record<string, string> = {
'feat': ':sparkles:',
'feature': ':sparkles:',
'fix': ':bug:',
'bug': ':bug:',
'hotfix': ':ambulance:',
'docs': ':memo:',
'documentation': ':memo:',
'style': ':lipstick:',
'refactor': ':recycle:',
'perf': ':zap:',
'performance': ':zap:',
'test': ':white_check_mark:',
'tests': ':white_check_mark:',
'build': ':construction_worker:',
'ci': ':green_heart:',
'chore': ':wrench:',
'revert': ':rewind:',
'wip': ':construction:',
'security': ':lock:',
'release': ':bookmark:',
'merge': ':twisted_rightwards_arrows:',
'mv': ':truck:',
'move': ':truck:',
'rename': ':truck:',
'remove': ':fire:',
'delete': ':fire:',
'add': ':sparkles:',
'create': ':sparkles:',
'implement': ':sparkles:',
'update': ':recycle:',
'improve': ':zap:',
'optimize': ':zap:',
'upgrade': ':arrow_up:',
'downgrade': ':arrow_down:',
'deploy': ':rocket:',
'init': ':tada:',
'initial': ':tada:',
};
const isGitmojiEntry = (value: unknown): value is GitmojiEntry => {
if (!value || typeof value !== 'object') return false;
const candidate = value as Record<string, unknown>;
@@ -111,6 +151,32 @@ const writeGitmojiCache = (gitmojis: GitmojiEntry[]) => {
const isGitmojiCacheFresh = (payload: GitmojiCachePayload) =>
Date.now() - payload.fetchedAt < GITMOJI_CACHE_TTL_MS;
const matchGitmojiFromSubject = (subject: string, gitmojis: GitmojiEntry[]): GitmojiEntry | null => {
const lowerSubject = subject.toLowerCase();
// 1. Check for conventional commit prefix (e.g. "feat:", "fix(scope):")
const conventionalRegex = /^([a-z]+)(?:\(.*\))?!?:/;
const match = lowerSubject.match(conventionalRegex);
if (match) {
const type = match[1];
// Map common types to gitmoji codes
const mappedCode = KEYWORD_MAP[type];
if (mappedCode) {
return gitmojis.find((g) => g.code === mappedCode) || null;
}
}
// 2. Check for starting words (e.g. "Add", "Fix")
const firstWord = lowerSubject.split(' ')[0];
const mappedCode = KEYWORD_MAP[firstWord];
if (mappedCode) {
return gitmojis.find((g) => g.code === mappedCode) || null;
}
return null;
};
let gitViewSnapshot: GitViewSnapshot | null = null;
const useEffectiveDirectory = () => {
@@ -551,7 +617,17 @@ export const GitView: React.FC = () => {
const highlights = Array.isArray(message.highlights) ? message.highlights : [];
if (subject) {
setCommitMessage(subject);
let finalSubject = subject;
if (settingsGitmojiEnabled && gitmojiEmojis.length > 0) {
const match = matchGitmojiFromSubject(subject, gitmojiEmojis);
if (match) {
const { code, emoji } = match;
if (!subject.startsWith(code) && !subject.startsWith(emoji)) {
finalSubject = `${code} ${subject}`;
}
}
}
setCommitMessage(finalSubject);
}
setGeneratedHighlights(highlights);
@@ -563,7 +639,7 @@ export const GitView: React.FC = () => {
} finally {
setIsGeneratingMessage(false);
}
}, [currentDirectory, selectedPaths, git]);
}, [currentDirectory, selectedPaths, git, settingsGitmojiEnabled, gitmojiEmojis]);
const handleCreateBranch = async (branchName: string) => {
if (!currentDirectory || !status) return;