-
Notifications
You must be signed in to change notification settings - Fork 45
feature(desktop): start of naive autocomplete #519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
📝 Walkthrough📝 WalkthroughPre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (15)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts (3)
58-61: Potential stale debounce invocation whendebounceMschanges.When
debounceMschanges, a new debounced function is created but any pending call from the previous instance isn't canceled. Consider canceling the old debounced function when creating a new one.🔎 Proposed fix
const debouncedFetch = useMemo( - () => debounce(fetchSuggestion, debounceMs), - [fetchSuggestion, debounceMs], + () => { + const fn = debounce(fetchSuggestion, debounceMs); + return fn; + }, + [fetchSuggestion, debounceMs], ); + +// Cancel previous debounce when it changes +useEffect(() => { + return () => { + debouncedFetch.cancel(); + }; +}, [debouncedFetch]);
83-89: Redundant cleanup effect.This cleanup effect duplicates the cleanup in lines 78-80. The first
useEffect(lines 64-81) already handles cleanup when the component unmounts or dependencies change. This second effect adds unnecessary complexity.🔎 Proposed removal
-// Clear on unmount -useEffect(() => { - return () => { - setSuggestion(null); - debouncedFetch.cancel(); - }; -}, [setSuggestion, debouncedFetch]);
91-94: Consider memoizing the return object to avoid unstable reference.The
suggestionselector is called inline in the return, creating a new store subscription each render. This is functionally correct but the returned object reference changes every render, which could cause unnecessary re-renders in consumers.🔎 Proposed fix
+const suggestion = useAutocompleteStore((s) => s.suggestion); + return { - suggestion: useAutocompleteStore((s) => s.suggestion), + suggestion, commandBuffer, };apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx (4)
11-16: Consider extractingHistoryItemtype to a shared location.This interface duplicates the structure returned by the tRPC endpoint. If the backend schema changes, this local type could drift. Consider importing or inferring the type from the tRPC router output.
🔎 Proposed approach
import type { inferRouterOutputs } from "@trpc/server"; import type { AppRouter } from "renderer/lib/trpc"; type RouterOutput = inferRouterOutputs<AppRouter>; type HistoryItem = RouterOutput["autocomplete"]["searchHistory"][number];
130-148:highlightMatchis recreated on every render.This function is defined inside the component and recreated each render. Since it doesn't depend on component state, consider extracting it outside the component or wrapping it in
useCallbackfor minor optimization.🔎 Proposed extraction
+// Move outside component +function highlightMatch(command: string, searchQuery: string) { + if (!searchQuery) return command; + + const lowerCommand = command.toLowerCase(); + const lowerQuery = searchQuery.toLowerCase(); + const index = lowerCommand.indexOf(lowerQuery); + + if (index === -1) return command; + + return ( + <> + {command.slice(0, index)} + <span className="text-orange-400 font-semibold"> + {command.slice(index, index + searchQuery.length)} + </span> + {command.slice(index + searchQuery.length)} + </> + ); +} + export function HistoryPicker({
165-181: Potential key collision when same command is recorded at the same millisecond.Using
${item.command}-${item.timestamp}as a key could cause collisions if the same command is recorded twice at the same timestamp. Consider adding an index fallback or using a unique ID if available from the backend.🔎 Proposed fix
-key={`${item.command}-${item.timestamp}`} +key={`${item.command}-${item.timestamp}-${index}`}
224-229: Empty state renders below the input bar instead of in the dropdown area.The empty state div is rendered after the input bar (lines 187-222), causing it to appear at the bottom. For visual consistency, consider rendering it in the same position as the results dropdown (before the input bar).
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx (2)
14-45: Consider extractingisLightColorto a shared utility.This luminance calculation could be useful elsewhere in the codebase (e.g., other terminal overlays, theming). Extracting it to a shared utils folder would improve reusability.
122-124: ContinuousrequestAnimationFrameloop while visible.The RAF loop runs continuously (~60fps) while the ghost text is visible. This could be optimized to only update when necessary (e.g., on terminal scroll, resize, or cursor movement events). For a "naive" implementation this is acceptable, but worth noting for future optimization.
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx (2)
42-76: Duplicated xterm internal API access pattern.This position calculation logic is nearly identical to
GhostText.tsx. Consider extracting a shared utility function likegetXtermCursorPosition(xterm)to reduce duplication and centralize the fragile internal API access.🔎 Proposed shared utility
// In a shared utils file, e.g., ../utils/xterm-helpers.ts interface CellDimensions { width: number; height: number; } interface CursorPosition { x: number; y: number; cellDimensions: CellDimensions; } export function getXtermCursorPosition(xterm: XTerm): CursorPosition | null { try { const core = (xterm as any)._core; const cellWidth = core?._renderService?.dimensions?.css?.cell?.width ?? 9; const cellHeight = core?._renderService?.dimensions?.css?.cell?.height ?? 17; return { x: xterm.buffer.active.cursorX * cellWidth, y: xterm.buffer.active.cursorY * cellHeight, cellDimensions: { width: cellWidth, height: cellHeight }, }; } catch { return null; } }
69-69: Magic number-100for horizontal positioning.The offset
-100is used to "center-ish" the dropdown but isn't documented. Consider extracting this as a named constant or calculating it based on dropdown width for better maintainability.🔎 Proposed improvement
+const DROPDOWN_HORIZONTAL_OFFSET = 100; // Center dropdown roughly under cursor + // Position dropdown below cursor -const x = Math.max(0, cursorX * cellWidth - 100); // Center-ish +const x = Math.max(0, cursorX * cellWidth - DROPDOWN_HORIZONTAL_OFFSET);apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts (1)
42-53: Hardcoded command list could be extracted as a constant.The list of path-taking commands (
cd,ls,cat, etc.) is embedded in the function. Extracting it as a module-level constant (or aSetfor O(1) lookup) would improve maintainability and allow easy extension.🔎 Proposed improvement
+const PATH_COMMANDS = new Set([ + "cd", + "ls", + "cat", + "vim", + "code", + "open", + "rm", + "cp", + "mv", + "mkdir", +]); + export function useFileCompletions({ cwd }: UseFileCompletionsOptions) { // ... const extractPathFromBuffer = useCallback((buffer: string): string | null => { // ... - if ( - lastToken && - (lastToken.includes("/") || - lastToken.startsWith(".") || - lastToken.startsWith("~") || - [ - "cd", - "ls", - "cat", - "vim", - "code", - "open", - "rm", - "cp", - "mv", - "mkdir", - ].includes(tokens[0])) - ) { + if ( + lastToken && + (lastToken.includes("/") || + lastToken.startsWith(".") || + lastToken.startsWith("~") || + PATH_COMMANDS.has(tokens[0])) + ) {apps/desktop/src/main/lib/command-history/osc-parser.ts (1)
44-46: Redundant RegExp construction.
OSC_133_REGEXis already defined with the global flag (/g). However, usingmatchAllon a regex with thegflag directly would work. The current approach of creating a new RegExp from.sourceis redundant but harmless.The static analysis warning about ReDoS is a false positive since the source is a trusted compile-time constant.
🔎 Simplify by reusing the existing regex
- // Find all matches using matchAll - const regex = new RegExp(OSC_133_REGEX.source, "g"); - for (const match of data.matchAll(regex)) { + // Find all matches using matchAll + for (const match of data.matchAll(OSC_133_REGEX)) {apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (1)
56-75: Consider consolidating store subscriptions.Each
useAutocompleteStorecall creates a separate subscription. For performance, consider using a single subscription with a selector that returns multiple values, or usinguseShallowfrom zustand if you need multiple primitive values:const { setCommandBuffer, clearCommandBuffer, ... } = useAutocompleteStore( useShallow((s) => ({ setCommandBuffer: s.setCommandBuffer, clearCommandBuffer: s.clearCommandBuffer, // ... })) );However, since these are mostly action functions (stable references), the current approach works correctly.
apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts (1)
117-118: Unused variable_endsWithSep.This variable is computed but never used. The underscore prefix suggests it's intentionally unused, but the computation can be removed to reduce confusion.
🔎 Remove unused variable
- // Check if partial ends with separator (user is in directory) - const _endsWithSep = - partial.endsWith("/") || partial.endsWith(path.sep); -
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (23)
apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.tsapps/desktop/src/lib/trpc/routers/autocomplete/index.tsapps/desktop/src/lib/trpc/routers/index.tsapps/desktop/src/main/lib/agent-setup/shell-wrappers.tsapps/desktop/src/main/lib/command-history/command-history.tsapps/desktop/src/main/lib/command-history/index.tsapps/desktop/src/main/lib/command-history/osc-parser.tsapps/desktop/src/main/lib/terminal/session.tsapps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Avoid using any type in TypeScript - maintain type safety unless absolutely necessary
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.tsapps/desktop/src/lib/trpc/routers/autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.tsapps/desktop/src/main/lib/command-history/index.tsapps/desktop/src/lib/trpc/routers/index.tsapps/desktop/src/main/lib/command-history/command-history.tsapps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/command-history/osc-parser.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/main/lib/terminal/session.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.tsapps/desktop/src/main/lib/agent-setup/shell-wrappers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
Run Biome for formatting, linting, import organization, and safe fixes at the root level using bun run lint:fix
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.tsapps/desktop/src/lib/trpc/routers/autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.tsapps/desktop/src/main/lib/command-history/index.tsapps/desktop/src/lib/trpc/routers/index.tsapps/desktop/src/main/lib/command-history/command-history.tsapps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/command-history/osc-parser.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/main/lib/terminal/session.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.tsapps/desktop/src/main/lib/agent-setup/shell-wrappers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
**/{components,features}/**/*.{ts,tsx,test.ts,test.tsx,stories.tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Co-locate component dependencies (utils, hooks, constants, config, tests, stories) next to the file using them
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
apps/desktop/src/renderer/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Never import Node.js modules in renderer process or shared code - use only in main process (src/main/)
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
apps/desktop/src/{main,renderer,preload}/**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use type-safe IPC communication - define channel types in apps/desktop/src/shared/ipc-channels.ts before implementing handlers
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.tsapps/desktop/src/main/lib/command-history/index.tsapps/desktop/src/main/lib/command-history/command-history.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/command-history/osc-parser.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/main/lib/terminal/session.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.tsapps/desktop/src/main/lib/agent-setup/shell-wrappers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
apps/desktop/**/*.{ts,tsx}
📄 CodeRabbit inference engine (apps/desktop/AGENTS.md)
apps/desktop/**/*.{ts,tsx}: For Electron interprocess communication, ALWAYS use tRPC as defined insrc/lib/trpc
Use alias as defined intsconfig.jsonwhen possible
Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
For tRPC subscriptions with trpc-electron, ALWAYS use the observable pattern from@trpc/server/observableinstead of async generators, as the library explicitly checksisObservable(result)and throws an error otherwise
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.tsapps/desktop/src/lib/trpc/routers/autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.tsapps/desktop/src/main/lib/command-history/index.tsapps/desktop/src/lib/trpc/routers/index.tsapps/desktop/src/main/lib/command-history/command-history.tsapps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/main/lib/command-history/osc-parser.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/main/lib/terminal/session.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.tsapps/desktop/src/main/lib/agent-setup/shell-wrappers.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
apps/desktop/src/main/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Accept object parameters in IPC handlers - do not use positional parameters in ipcMain.handle()
Files:
apps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/main/lib/command-history/index.tsapps/desktop/src/main/lib/command-history/command-history.tsapps/desktop/src/main/lib/command-history/osc-parser.tsapps/desktop/src/main/lib/terminal/session.tsapps/desktop/src/main/lib/agent-setup/shell-wrappers.ts
**/{components,features}/**/[!.]*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
Organize project structure with one folder per component: ComponentName/ComponentName.tsx with index.ts barrel export
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
**/*.{tsx,css}
📄 CodeRabbit inference engine (AGENTS.md)
Use React + TailwindCSS v4 + shadcn/ui for UI development
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
**/{components,features}/**/*.tsx
📄 CodeRabbit inference engine (AGENTS.md)
**/{components,features}/**/*.tsx: Nest components in parent's components/ folder if used only once, promote to highest shared parent's components/ if used 2+ times
Use one component per file - do not combine multiple components in a single file
Files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
🧠 Learnings (5)
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Use alias as defined in `tsconfig.json` when possible
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
📚 Learning: 2025-12-18T23:19:10.415Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T23:19:10.415Z
Learning: Applies to apps/desktop/src/{main,renderer,preload}/**/*.{ts,tsx} : Use type-safe IPC communication - define channel types in apps/desktop/src/shared/ipc-channels.ts before implementing handlers
Applied to files:
apps/desktop/src/main/lib/terminal/types.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
📚 Learning: 2025-12-18T23:19:10.415Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T23:19:10.415Z
Learning: Applies to **/{components,features}/**/[!.]*.tsx : Organize project structure with one folder per component: ComponentName/ComponentName.tsx with index.ts barrel export
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
📚 Learning: 2025-12-18T23:19:10.415Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-18T23:19:10.415Z
Learning: Applies to **/{components,features}/**/*.{ts,tsx,test.ts,test.tsx,stories.tsx} : Co-locate component dependencies (utils, hooks, constants, config, tests, stories) next to the file using them
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
📚 Learning: 2025-12-21T04:39:28.543Z
Learnt from: CR
Repo: superset-sh/superset PR: 0
File: apps/desktop/AGENTS.md:0-0
Timestamp: 2025-12-21T04:39:28.543Z
Learning: Applies to apps/desktop/**/*.{ts,tsx} : Prefer zustand for state management if it makes sense. Do not use effect unless absolutely necessary.
Applied to files:
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
🧬 Code graph analysis (9)
apps/desktop/src/main/lib/terminal/types.ts (2)
apps/desktop/src/main/lib/command-history/index.ts (1)
CommandTracker(7-7)apps/desktop/src/main/lib/command-history/osc-parser.ts (1)
CommandTracker(75-112)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx (2)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts (2)
GhostText(2-2)useAutocompleteStore(5-5)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts (1)
useAutocompleteStore(64-134)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts (1)
useAutocompleteStore(64-134)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts (1)
useAutocompleteStore(64-134)
apps/desktop/src/lib/trpc/routers/index.ts (1)
apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts (1)
createAutocompleteRouter(15-209)
apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts (4)
apps/desktop/src/lib/trpc/routers/autocomplete/index.ts (1)
createAutocompleteRouter(1-1)apps/desktop/src/lib/trpc/index.ts (1)
router(47-47)apps/desktop/src/main/lib/command-history/command-history.ts (1)
commandHistoryManager(250-250)apps/desktop/src/main/lib/command-history/index.ts (1)
commandHistoryManager(3-3)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (10)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts (6)
useAutocompleteStore(5-5)useGhostSuggestion(4-4)useFileCompletions(4-4)GhostText(2-2)HistoryPicker(3-3)CompletionDropdown(1-1)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts (1)
useAutocompleteStore(64-134)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts (1)
useGhostSuggestion(16-95)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts (1)
useFileCompletions(13-102)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx (1)
GhostText(53-168)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts (1)
GhostText(1-1)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx (1)
HistoryPicker(22-232)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts (1)
HistoryPicker(1-1)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx (1)
CompletionDropdown(21-194)apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.ts (1)
CompletionDropdown(1-1)
apps/desktop/src/main/lib/terminal/session.ts (3)
apps/desktop/src/main/lib/command-history/osc-parser.ts (2)
CommandTracker(75-112)parseOscSequences(37-69)apps/desktop/src/main/lib/command-history/command-history.ts (1)
commandHistoryManager(250-250)apps/desktop/src/main/lib/terminal-escape-filter.ts (2)
containsClearScrollbackSequence(29-31)extractContentAfterClear(38-46)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx (1)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts (1)
useAutocompleteStore(64-134)
🪛 ast-grep (0.40.3)
apps/desktop/src/main/lib/command-history/osc-parser.ts
[warning] 44-44: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(OSC_133_REGEX.source, "g")
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: Build
🔇 Additional comments (30)
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts (1)
1-1: LGTM!Standard barrel export pattern for the GhostText component.
apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts (1)
29-48: LGTM - Correct OSC 133 sequence emission for zsh.The zsh implementation correctly emits OSC 133;C (command start) before execution via
preexecand OSC 133;D (command done) after execution viaprecmd. The control character stripping in the command text is a good security practice.apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts (1)
1-1: LGTM!Standard barrel export for the HistoryPicker component.
apps/desktop/src/lib/trpc/routers/autocomplete/index.ts (1)
1-1: LGTM!Standard barrel export for the autocomplete router factory.
apps/desktop/src/main/lib/terminal/types.ts (1)
2-2: LGTM - Clean type-safe integration.The optional
commandTrackerproperty is properly typed and follows the existing pattern inTerminalSession. The type-only import is appropriate.Also applies to: 20-20
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts (1)
1-2: LGTM!Clean barrel exports for autocomplete hooks following the established pattern.
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.ts (1)
1-1: LGTM!Standard barrel export for the CompletionDropdown component.
apps/desktop/src/lib/trpc/routers/index.ts (1)
6-6: LGTM - Proper router integration.The autocomplete router is correctly imported and wired into the main application router, following the established pattern used by other domain routers in the codebase.
Also applies to: 33-33
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts (1)
1-4: LGTM!Clean barrel export following the project's component organization pattern with proper type-only export syntax.
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx (1)
53-167: Overall implementation looks solid for the initial naive approach.The component handles visibility, positioning, and styling appropriately. The use of RAF for position tracking, while not optimal, ensures the ghost text stays aligned with the cursor. Error handling with try/catch and null fallbacks is good defensive programming.
apps/desktop/src/main/lib/command-history/index.ts (1)
1-12: LGTM!Clean barrel export consolidating the command-history module's public API with proper type-only export syntax.
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts (1)
1-5: LGTM!Well-organized barrel export providing a clean public API for the Autocomplete feature. Follows the project's component organization guidelines.
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx (1)
91-132: Keyboard handler logic is well-structured.Good use of
useCallbackwith proper dependencies. The capture phase listener ensures the dropdown intercepts keys before the terminal. The navigation logic correctly handles bounds checking.apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts (2)
28-59: Path extraction doesn't handle quoted strings or escape sequences.Commands like
cat "my file.txt"orcat my\ file.txtwon't be parsed correctly. For a "naive" implementation this is acceptable, but worth noting as a future improvement area.
13-101: Overall hook structure is clean and follows best practices.Good use of
useCallbackfor memoization, proper dependency arrays, and clean error handling. The tRPC integration viauseUtils()for imperative fetching is appropriate for this use case.apps/desktop/src/main/lib/terminal/session.ts (1)
168-192: LGTM!The OSC 133 parsing integration is well-structured: sequences are parsed first, events are processed through the command tracker, and cleaned data flows to storage, history, port scanning, and the renderer. The optional chaining on
commandTrackerprovides safe handling.apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2)
180-194: LGTM!The extended
KeyboardHandlerOptionsinterface cleanly exposes the necessary callbacks and state accessors for autocomplete integration. The optional properties maintain backward compatibility.
282-341: LGTM!The keyboard handling additions are well-implemented:
- Ctrl+R correctly intercepts before the shell receives it
- Right Arrow acceptance checks for valid prefix match before accepting
- Escape closes dropdown only when open
- Tab completion is intentionally deferred with a clear TODO
apps/desktop/src/main/lib/command-history/osc-parser.ts (2)
27-31: LGTM!The regex pattern correctly captures OSC 133;C (command start) and OSC 133;D (command done) sequences with both ST terminators (ESC \ and BEL). The biome-ignore comment appropriately justifies the control character usage.
75-112: LGTM!The
CommandTrackeris a clean state machine implementation. It correctly correlates command_start and command_done events, gracefully handles orphaned done events, and provides utility methods for inspection and cleanup.apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx (4)
405-434: LGTM!The autocomplete callbacks correctly use
useAutocompleteStore.getState()to access current state synchronously within event handlers, avoiding stale closure issues. TheonAcceptSuggestionhandler properly updates both the local ref and the store.
479-497: LGTM!The cleanup properly resets autocomplete state (command buffer, history picker, completion dropdown) on unmount. Including zustand actions in the dependency array is safe since they're stable references, though verbose.
527-541: Shell-specific line clearing may not work universally.Line 532 uses
\x15(Ctrl+U) to clear the line before inserting the selected command. This works in bash/zsh but may behave differently in other shells (e.g., fish, PowerShell). For a "naive" first implementation this is acceptable, but consider documenting this limitation or exploring shell-agnostic approaches in the future.
576-600: LGTM!The autocomplete UI components are cleanly integrated with appropriate visibility conditions. The ghost text only shows when focused and no modals are open, which prevents visual conflicts.
apps/desktop/src/main/lib/command-history/command-history.ts (3)
28-89: LGTM!The database initialization is well-structured with WAL mode for better concurrency, proper schema creation, FTS5 virtual table with sync triggers, and appropriate indexes. The lazy initialization pattern ensures the DB is only created when needed.
139-170: FTS5 query escaping handles common cases but may have edge cases.The escaping strategy (remove quotes, wrap terms in
"term"*) works for typical queries. However, FTS5 has other special characters (:,-,^, etc.) that could cause unexpected behavior if passed through. For a naive implementation this is acceptable, but consider more robust escaping if issues arise.The parameterized queries correctly prevent SQL injection.
102-106: Noise filtering excludes single-character commands.The
length < 2filter removes legitimate single-character shell commands (e.g.,w,qif aliased). This is a reasonable tradeoff for reducing noise, but worth noting if users report missing history entries.apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts (1)
64-109: LGTM!The store implementation follows zustand best practices with clean action implementations. The
clearCommandBufferaction correctly resets related suggestion state alongside the buffer. Based on learnings, zustand is the preferred state management choice for this codebase.apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts (2)
99-207: LGTM!The
listCompletionsprocedure correctly handles path resolution, directory listing, filtering, and completion text generation. The path traversal is intentional for file path completion. Error handling gracefully returns empty results with an error message. The 50-item limit prevents excessive results.
214-239: LGTM!The
getFileIconhelper provides reasonable icon mapping for common file types with a sensible default fallback.
| _superset_last_cmd="" | ||
| _superset_trap_debug() { | ||
| # Capture the command before execution | ||
| _superset_last_cmd="$BASH_COMMAND" | ||
| } | ||
| _superset_prompt_command() { | ||
| local exit_code=$? | ||
| # Emit command done with exit code | ||
| printf '\\033]133;D;%d\\033\\\\' "$exit_code" | ||
| # Emit command start when we have a captured command | ||
| if [[ -n "$_superset_last_cmd" && "$_superset_last_cmd" != "_superset_prompt_command" ]]; then | ||
| printf '\\033]133;C;%s\\033\\\\' "\${_superset_last_cmd//[[:cntrl:]]}" | ||
| fi | ||
| _superset_last_cmd="" | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Critical: OSC 133 sequence order is incorrect for bash.
The bash implementation emits the C (command start) sequence in PROMPT_COMMAND (line 95), which runs after the command completes. According to OSC 133 semantics, C should be emitted before the command executes, and D should be emitted after.
The correct flow should be:
- DEBUG trap fires (before execution) → emit C with command
- Command executes
- PROMPT_COMMAND fires (after execution) → emit D with exit code
Currently, both C and D are emitted in PROMPT_COMMAND after the command completes, which will produce incorrect command tracking timestamps and ordering.
🔎 Proposed fix
_superset_last_cmd=""
_superset_trap_debug() {
# Capture the command before execution
_superset_last_cmd="$BASH_COMMAND"
+ # Emit command start when we have a command
+ if [[ -n "$_superset_last_cmd" && "$_superset_last_cmd" != "_superset_prompt_command" ]]; then
+ printf '\033]133;C;%s\033\\' "${_superset_last_cmd//[[:cntrl:]]}"
+ fi
}
_superset_prompt_command() {
local exit_code=$?
# Emit command done with exit code
printf '\033]133;D;%d\033\\' "$exit_code"
- # Emit command start when we have a captured command
- if [[ -n "$_superset_last_cmd" && "$_superset_last_cmd" != "_superset_prompt_command" ]]; then
- printf '\033]133;C;%s\033\\' "${_superset_last_cmd//[[:cntrl:]]}"
- fi
_superset_last_cmd=""
}📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| _superset_last_cmd="" | |
| _superset_trap_debug() { | |
| # Capture the command before execution | |
| _superset_last_cmd="$BASH_COMMAND" | |
| } | |
| _superset_prompt_command() { | |
| local exit_code=$? | |
| # Emit command done with exit code | |
| printf '\\033]133;D;%d\\033\\\\' "$exit_code" | |
| # Emit command start when we have a captured command | |
| if [[ -n "$_superset_last_cmd" && "$_superset_last_cmd" != "_superset_prompt_command" ]]; then | |
| printf '\\033]133;C;%s\\033\\\\' "\${_superset_last_cmd//[[:cntrl:]]}" | |
| fi | |
| _superset_last_cmd="" | |
| } | |
| _superset_last_cmd="" | |
| _superset_trap_debug() { | |
| # Capture the command before execution | |
| _superset_last_cmd="$BASH_COMMAND" | |
| # Emit command start when we have a command | |
| if [[ -n "$_superset_last_cmd" && "$_superset_last_cmd" != "_superset_prompt_command" ]]; then | |
| printf '\\033]133;C;%s\\033\\\\' "\${_superset_last_cmd//[[:cntrl:]]}" | |
| fi | |
| } | |
| _superset_prompt_command() { | |
| local exit_code=$? | |
| # Emit command done with exit code | |
| printf '\\033]133;D;%d\\033\\\\' "$exit_code" | |
| _superset_last_cmd="" | |
| } |
🤖 Prompt for AI Agents
In apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts around lines 84 to
98, the OSC 133 sequences are emitted in the wrong order because C (command
start) is produced in PROMPT_COMMAND which runs after the command; change the
logic so the DEBUG trap captures and immediately emits the C sequence with the
sanitized command before the command runs, and modify PROMPT_COMMAND to only
emit the D sequence with the exit code after the command completes; ensure the
DEBUG handler skips emitting when the command is the prompt handler itself,
properly escapes control chars in the emitted command, and clears any stored
last-command state in PROMPT_COMMAND after emitting D.
| // Create command tracker for history recording | ||
| const commandTracker = new CommandTracker((command, exitCode) => { | ||
| commandHistoryManager.record({ | ||
| command, | ||
| workspaceId, | ||
| cwd: workingDir, | ||
| exitCode, | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cwd captured here is the initial working directory, not the current one.
When recording commands, the workingDir used is the value at session creation time. If the user changes directories during the session (e.g., via cd), commands will be recorded with a stale cwd. Consider tracking the current working directory dynamically (e.g., via OSC 7 sequences parsed elsewhere) and passing it to the tracker callback.
🤖 Prompt for AI Agents
In apps/desktop/src/main/lib/terminal/session.ts around lines 128-136, the
command tracker currently records cwd using the session's initial workingDir
which becomes stale after directory changes; modify the tracker callback to use
a dynamically-updated current working directory (the variable your OSC 7 / cwd
parser updates) instead of the initial workingDir — either pass the currentCwd
into the CommandTracker callback when invoked or have the callback read the
session's currentCwd property that is updated by your OSC7 handler; ensure the
OSC7 parsing code updates that shared currentCwd value whenever the terminal
reports a new cwd so recorded commands have the correct, up-to-date cwd.
| // Get cell dimensions from xterm's internal renderer | ||
| // @ts-expect-error - accessing internal property | ||
| const dims = xterm._core?._renderService?.dimensions; | ||
| const cellWidth = dims?.css?.cell?.width ?? 9; | ||
| const cellHeight = dims?.css?.cell?.height ?? 17; | ||
|
|
||
| setCellDimensions({ width: cellWidth, height: cellHeight }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
xterm.js get cell dimensions width height public API
💡 Result:
Short answer: xterm.js does not expose a supported public API that directly returns a cell's pixel width/height.
Options you can use:
-
Compute it yourself: measure the terminal DOM element and divide by cols/rows:
cellWidth = terminal.element.getBoundingClientRect().width / terminal.cols
cellHeight = terminal.element.getBoundingClientRect().height / terminal.rows.
(Terminal.cols/rows and .open/element are public.) [1][2] -
Undocumented/private (fragile): some apps read internal values like
(terminal as any)._core._renderService.dimensions.actualCellWidth / actualCellHeight — this works in practice but is private and may break across xterm.js versions. [3] -
For terminal-side reports there is DECPS/CSI support (getCellSizePixels / reporting sequences) exposed in the window options / VT features if you want the terminal to reply with pixel sizes. [4]
References:
- Terminal API (cols/rows, open). [1]
- Terminal class docs / element measurement note. [1]
- Example using private _core._renderService.dimensions in Hyper. [3]
- IWindowOptions getCellSizePixels / CSI reports. [4]
🌐 Web query:
xterm.js charWidth charHeight options
💡 Result:
Short answer: xterm.js does not expose public options named charWidth or charHeight. Character size is derived from the font settings (fontSize, fontFamily, lineHeight) and measured internally by the CharMeasure/WidthCache used by the renderer. To change character dimensions, set Terminal options like fontSize, fontFamily and lineHeight; xterm.js will measure those values at runtime. Internal measurement utilities exist in the renderer (CharMeasure / WidthCache) but are not part of the public options API (using them requires relying on internal APIs). [1][2][3]
Useful links:
- Terminal options (fontSize, fontFamily, lineHeight, etc.). [1]
- xterm.js repository / README. [2]
- DOM renderer: Char/width measurement (CharMeasure / WidthCache) — internal implementation. [3]
References:
[1] xterm.js ITerminalOptions documentation — lists fontSize, fontFamily, lineHeight and other terminal options.
[2] xterm.js GitHub repo (project README).
[3] DOM renderer source/docs describing CharMeasure / WidthCache (internal measurement implementation).
🏁 Script executed:
# Search for how xterm cell dimensions are used in the codebase
rg "cellWidth|cellHeight|dimensions" apps/desktop/src/renderer --type ts --type tsx -B 2 -A 2Repository: superset-sh/superset
Length of output: 91
🏁 Script executed:
# Check if there are other usages of _core or _renderService in the codebase
rg "_core\.|_renderService" apps/desktop/src/renderer --type ts --type tsxRepository: superset-sh/superset
Length of output: 91
🏁 Script executed:
# Search for xterm imports and usage patterns in renderer
rg "xterm|Terminal" apps/desktop/src/renderer --type ts -B 1 -A 1 | head -50Repository: superset-sh/superset
Length of output: 3671
🏁 Script executed:
# Look at the GhostText component to understand where xterm comes from
cat -n apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx | head -50Repository: superset-sh/superset
Length of output: 1857
🏁 Script executed:
# Continue reading the GhostText.tsx file to see the context around line 100-106
cat -n apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx | sed -n '90,115p'Repository: superset-sh/superset
Length of output: 1066
🏁 Script executed:
# Check if Terminal has cols, rows, and element properties used elsewhere
rg "xterm\.(cols|rows|element)" apps/desktop/src/renderer --type ts -B 2 -A 2Repository: superset-sh/superset
Length of output: 6569
Replace internal xterm API access with DOM measurement.
The code currently accesses xterm._core._renderService.dimensions (internal API) with fallback values 9 and 17. Instead, use the public API: measure the container and calculate cell dimensions as cellWidth = container.getBoundingClientRect().width / xterm.cols and cellHeight = container.getBoundingClientRect().height / xterm.rows. The xterm.element, xterm.cols, and xterm.rows properties are all public and already available in this component.
| const partial = extractPathFromBuffer(commandBuffer); | ||
| if (!partial && commandBuffer.trim()) { | ||
| // No path context, but there's content - might be after a command | ||
| // Try completing with empty partial (list cwd) | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Empty conditional block with dangling comment.
This block has a comment but no implementation. Either implement the intended behavior or remove the dead code. As-is, the partial fallback to empty string on line 75 handles this case.
🔎 Proposed fix - remove dead code
const partial = extractPathFromBuffer(commandBuffer);
-if (!partial && commandBuffer.trim()) {
- // No path context, but there's content - might be after a command
- // Try completing with empty partial (list cwd)
-}
try {📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const partial = extractPathFromBuffer(commandBuffer); | |
| if (!partial && commandBuffer.trim()) { | |
| // No path context, but there's content - might be after a command | |
| // Try completing with empty partial (list cwd) | |
| } | |
| const partial = extractPathFromBuffer(commandBuffer); | |
| try { |
🤖 Prompt for AI Agents
In
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
around lines 67-71 there is an empty if block with only a comment left behind;
remove that dead conditional (the later fallback that sets partial to empty
already covers this case) so the code has no no-op branch, delete the if block
and its comment, and run lint/tests to ensure no remaining references rely on
that empty branch.
| selectNextCompletion: () => { | ||
| set((state) => ({ | ||
| selectedCompletionIndex: | ||
| (state.selectedCompletionIndex + 1) % state.completions.length, | ||
| })); | ||
| }, | ||
|
|
||
| selectPrevCompletion: () => { | ||
| set((state) => ({ | ||
| selectedCompletionIndex: | ||
| (state.selectedCompletionIndex - 1 + state.completions.length) % | ||
| state.completions.length, | ||
| })); | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Division by zero when completions array is empty.
selectNextCompletion and selectPrevCompletion use modulo with completions.length. If called when completions is empty, this produces NaN or incorrect behavior.
🔎 Add guard for empty completions
selectNextCompletion: () => {
- set((state) => ({
- selectedCompletionIndex:
- (state.selectedCompletionIndex + 1) % state.completions.length,
- }));
+ set((state) => {
+ if (state.completions.length === 0) return state;
+ return {
+ selectedCompletionIndex:
+ (state.selectedCompletionIndex + 1) % state.completions.length,
+ };
+ });
},
selectPrevCompletion: () => {
- set((state) => ({
- selectedCompletionIndex:
- (state.selectedCompletionIndex - 1 + state.completions.length) %
- state.completions.length,
- }));
+ set((state) => {
+ if (state.completions.length === 0) return state;
+ return {
+ selectedCompletionIndex:
+ (state.selectedCompletionIndex - 1 + state.completions.length) %
+ state.completions.length,
+ };
+ });
},📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| selectNextCompletion: () => { | |
| set((state) => ({ | |
| selectedCompletionIndex: | |
| (state.selectedCompletionIndex + 1) % state.completions.length, | |
| })); | |
| }, | |
| selectPrevCompletion: () => { | |
| set((state) => ({ | |
| selectedCompletionIndex: | |
| (state.selectedCompletionIndex - 1 + state.completions.length) % | |
| state.completions.length, | |
| })); | |
| }, | |
| selectNextCompletion: () => { | |
| set((state) => { | |
| if (state.completions.length === 0) return state; | |
| return { | |
| selectedCompletionIndex: | |
| (state.selectedCompletionIndex + 1) % state.completions.length, | |
| }; | |
| }); | |
| }, | |
| selectPrevCompletion: () => { | |
| set((state) => { | |
| if (state.completions.length === 0) return state; | |
| return { | |
| selectedCompletionIndex: | |
| (state.selectedCompletionIndex - 1 + state.completions.length) % | |
| state.completions.length, | |
| }; | |
| }); | |
| }, |
🤖 Prompt for AI Agents
In
apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
around lines 111 to 124, the next/previous selection logic uses modulo with
completions.length which will divide by zero when the completions array is
empty; add an early guard that checks if state.completions.length === 0 and
return (or set selectedCompletionIndex to -1) before performing the modulo math,
otherwise compute the new index as currently implemented so modulo is only used
when length > 0.
Description
Related Issues
Type of Change
Testing
Screenshots (if applicable)
Additional Notes
Summary by CodeRabbit
Release Notes
✏️ Tip: You can customize this high-level summary in your review settings.