Skip to content

Conversation

@AviPeltz
Copy link
Collaborator

@AviPeltz AviPeltz commented Dec 28, 2025

Description

Related Issues

Type of Change

  • Bug fix
  • New feature
  • Documentation
  • Refactor
  • Other (please describe):

Testing

Screenshots (if applicable)

Additional Notes

Summary by CodeRabbit

Release Notes

  • New Features
    • Added command history search and autocomplete for terminal input
    • Ghost text suggestions display recently used commands inline
    • File and directory path completions triggered by Tab key
    • History picker dropdown for browsing and selecting previous commands

✏️ Tip: You can customize this high-level summary in your review settings.

@AviPeltz AviPeltz marked this pull request as draft December 28, 2025 01:44
@coderabbitai
Copy link

coderabbitai bot commented Dec 28, 2025

📝 Walkthrough
📝 Walkthrough

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Description check ⚠️ Warning The pull request description uses only the template structure with no substantive content filled in any section. Fill in the Description section with a clear explanation of the autocomplete feature being added, link any related issues, and describe the testing performed.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feature(desktop): start of naive autocomplete' clearly and concisely describes the primary change: introducing an autocomplete feature for the desktop application.
Docstring Coverage ✅ Passed Docstring coverage is 84.62% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch autocomplete

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a 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 when debounceMs changes.

When debounceMs changes, 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 suggestion selector 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 extracting HistoryItem type 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: highlightMatch is 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 useCallback for 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 extracting isLightColor to 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: Continuous requestAnimationFrame loop 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 like getXtermCursorPosition(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 -100 for horizontal positioning.

The offset -100 is 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 a Set for 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_REGEX is already defined with the global flag (/g). However, using matchAll on a regex with the g flag directly would work. The current approach of creating a new RegExp from .source is 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 useAutocompleteStore call creates a separate subscription. For performance, consider using a single subscription with a selector that returns multiple values, or using useShallow from 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

📥 Commits

Reviewing files that changed from the base of the PR and between 436b5f1 and 5002625.

📒 Files selected for processing (23)
  • apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts
  • apps/desktop/src/lib/trpc/routers/autocomplete/index.ts
  • apps/desktop/src/lib/trpc/routers/index.ts
  • apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts
  • apps/desktop/src/main/lib/command-history/command-history.ts
  • apps/desktop/src/main/lib/command-history/index.ts
  • apps/desktop/src/main/lib/command-history/osc-parser.ts
  • apps/desktop/src/main/lib/terminal/session.ts
  • apps/desktop/src/main/lib/terminal/types.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/HistoryPicker.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/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.ts
  • apps/desktop/src/main/lib/terminal/types.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
  • apps/desktop/src/lib/trpc/routers/autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts
  • apps/desktop/src/main/lib/command-history/index.ts
  • apps/desktop/src/lib/trpc/routers/index.ts
  • apps/desktop/src/main/lib/command-history/command-history.ts
  • apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/main/lib/command-history/osc-parser.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/desktop/src/main/lib/terminal/session.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts
  • apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts
  • apps/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.ts
  • apps/desktop/src/main/lib/terminal/types.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
  • apps/desktop/src/lib/trpc/routers/autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts
  • apps/desktop/src/main/lib/command-history/index.ts
  • apps/desktop/src/lib/trpc/routers/index.ts
  • apps/desktop/src/main/lib/command-history/command-history.ts
  • apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/main/lib/command-history/osc-parser.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/desktop/src/main/lib/terminal/session.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts
  • apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts
  • apps/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.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts
  • apps/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.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts
  • apps/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.ts
  • apps/desktop/src/main/lib/terminal/types.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts
  • apps/desktop/src/main/lib/command-history/index.ts
  • apps/desktop/src/main/lib/command-history/command-history.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/main/lib/command-history/osc-parser.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/desktop/src/main/lib/terminal/session.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts
  • apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts
  • apps/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 in src/lib/trpc
Use alias as defined in tsconfig.json when 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/observable instead of async generators, as the library explicitly checks isObservable(result) and throws an error otherwise

Files:

  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/index.ts
  • apps/desktop/src/main/lib/terminal/types.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/GhostText.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useFileCompletions.ts
  • apps/desktop/src/lib/trpc/routers/autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/useGhostSuggestion.ts
  • apps/desktop/src/main/lib/command-history/index.ts
  • apps/desktop/src/lib/trpc/routers/index.ts
  • apps/desktop/src/main/lib/command-history/command-history.ts
  • apps/desktop/src/lib/trpc/routers/autocomplete/autocomplete.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/autocomplete-store.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/desktop/src/main/lib/command-history/osc-parser.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/desktop/src/main/lib/terminal/session.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/hooks/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/HistoryPicker/index.ts
  • apps/desktop/src/main/lib/agent-setup/shell-wrappers.ts
  • apps/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.ts
  • apps/desktop/src/main/lib/command-history/index.ts
  • apps/desktop/src/main/lib/command-history/command-history.ts
  • apps/desktop/src/main/lib/command-history/osc-parser.ts
  • apps/desktop/src/main/lib/terminal/session.ts
  • apps/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.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/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.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/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.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/CompletionDropdown/CompletionDropdown.tsx
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Terminal.tsx
  • apps/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.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/index.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/GhostText/index.ts
  • apps/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.ts
  • apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/Autocomplete/stores/index.ts
  • apps/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.ts
  • apps/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.ts
  • apps/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 preexec and OSC 133;D (command done) after execution via precmd. 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 commandTracker property is properly typed and follows the existing pattern in TerminalSession. 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 useCallback with 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" or cat my\ file.txt won'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 useCallback for memoization, proper dependency arrays, and clean error handling. The tRPC integration via useUtils() 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 commandTracker provides safe handling.

apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/Terminal/helpers.ts (2)

180-194: LGTM!

The extended KeyboardHandlerOptions interface 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 CommandTracker is 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. The onAcceptSuggestion handler 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 < 2 filter removes legitimate single-character shell commands (e.g., w, q if 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 clearCommandBuffer action 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 listCompletions procedure 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 getFileIcon helper provides reasonable icon mapping for common file types with a sensible default fallback.

Comment on lines +84 to +98
_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=""
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

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:

  1. DEBUG trap fires (before execution) → emit C with command
  2. Command executes
  3. 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.

Suggested change
_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.

Comment on lines +128 to +136
// Create command tracker for history recording
const commandTracker = new CommandTracker((command, exitCode) => {
commandHistoryManager.record({
command,
workspaceId,
cwd: workingDir,
exitCode,
});
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Comment on lines +100 to +106
// 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 });
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 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:

  1. Terminal API (cols/rows, open). [1]
  2. Terminal class docs / element measurement note. [1]
  3. Example using private _core._renderService.dimensions in Hyper. [3]
  4. 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 2

Repository: 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 tsx

Repository: 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 -50

Repository: 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 -50

Repository: 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 2

Repository: 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.

Comment on lines +67 to +71
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)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Comment on lines +111 to +124
selectNextCompletion: () => {
set((state) => ({
selectedCompletionIndex:
(state.selectedCompletionIndex + 1) % state.completions.length,
}));
},

selectPrevCompletion: () => {
set((state) => ({
selectedCompletionIndex:
(state.selectedCompletionIndex - 1 + state.completions.length) %
state.completions.length,
}));
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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.

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants