Skip to main content

React + TypeScript + Vite

This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules. Currently, two official plugins are available:

Expanding the ESLint configuration

If you are developing a production application, we recommend updating the configuration to enable type-aware lint rules:
export default tseslint.config({
  extends: [
    // Remove ...tseslint.configs.recommended and replace with this
    ...tseslint.configs.recommendedTypeChecked,
    // Alternatively, use this for stricter rules
    ...tseslint.configs.strictTypeChecked,
    // Optionally, add this for stylistic rules
    ...tseslint.configs.stylisticTypeChecked,
  ],
  languageOptions: {
    // other options...
    parserOptions: {
      project: ['./tsconfig.node.json', './tsconfig.app.json'],
      tsconfigRootDir: import.meta.dirname,
    },
  },
})
You can also install eslint-plugin-react-x and eslint-plugin-react-dom for React-specific rules:
// eslint.config.js
import reactX from 'eslint-plugin-react-x'
import reactDom from 'eslint-plugin-react-dom'

export default tseslint.config({
  plugins: {
    // Add the react-x and react-dom plugins
    'react-x': reactX,
    'react-dom': reactDom,
  },
  rules: {
    // other options...
    // Enable its recommended typescript rules
    ...reactX.configs['recommended-typescript'].rules,
    ...reactDom.configs.recommended.rules,
  },
})

Project Settings layout

Project settings have been moved from dialog/drawer variants to a dedicated page at /projects/:projectId/settings.
  • The ProjectSettingsPage component provides a full-page settings experience with 5 sections:
    • General - Project name, repository URL, and ticket numbering
    • Agents - Default agent selection
    • Scripts - Pre/post ticket enhancement scripts
    • GitHub - Issue sync and auto-close settings
    • Inline Agents - Configure inline agent behavior
  • The page uses MasterDetailLayout for consistent sidebar navigation
  • Settings sections use a consistent card-based layout with polished typography
  • Each section component (TicketNumberingForm, RepositoryDefaultsForm, AgentDefaultsForm, ScriptsForm, GithubIssueSyncSection, InlineAgentForm) follows the same design pattern

MasterDetailLayout

The MasterDetailLayout<T> component provides a consistent sidebar navigation pattern used across the application with generic type support for strongly-typed items:
import {MasterDetailLayout, type MasterDetailItem} from '@/components/layout/MasterDetailLayout'

interface MyItem extends MasterDetailItem {
  cardId: string
  worktreePath: string
}

<MasterDetailLayout<MyItem>
  title="Workstations"
  items={items}
  activeId={activeId}
  onSelect={handleSelect}
  renderItem={renderItem}
  sidebarFooter={sidebarFooter}>
  {content}
</MasterDetailLayout<MyItem>>

Props

PropTypeDescription
titlestringPage title displayed in header
itemsT[]Array of items to display in sidebar
activeIdstring | nullID of currently active/selected item
onSelect(id: string) => voidCallback when item is selected
renderItem(item: T, isActive: boolean, defaultRender: () => ReactNode) => ReactNodeCustom renderer for sidebar items (receives defaultRender callback for fallback)
sidebarFooterReactNode | nullContent to render at bottom of sidebar (e.g., Quick Launch)
sidebarClassNamestringAdditional CSS classes for sidebar
loadingbooleanShow loading state in sidebar
emptyStateReactNodeContent when sidebar is empty

MasterDetailItem Interface

Base interface for sidebar items:
interface MasterDetailItem {
  id: string
  label: string
  subtitle?: string
  icon?: React.ComponentType<{className?: string}>
  disabled?: boolean
}
This layout is used by:
  • ProjectSettingsPage - Project settings with section navigation
  • AgentsPage - Agent selection and management
  • TerminalsToolWindow - Terminal sessions with worktree list

Hooks

useAttemptConversationPagination

A React hook for managing paginated loading of attempt conversation messages with automatic initial load and manual pagination support.
const {
  messages,        // ConversationItem[] - loaded messages
  hasMore,         // boolean - whether more messages are available
  isLoading,       // boolean - initial load state
  isFetchingMore,  // boolean - pagination load state
  loadMore,        // () => Promise<void> - load next page
  appendNewMessage,// (item: ConversationItem) => void - add new message
  reset,           // () => void - reset state
} = useAttemptConversationPagination({
  attemptId: string | undefined,
  pageSize?: number,  // default 25
  enabled?: boolean   // default true
})
The hook handles:
  • Automatic initial message load when attemptId changes
  • Pagination with configurable page size
  • Duplicate prevention when appending new messages
  • Proper cleanup and state reset on attempt change

New Pages

The sidebar refactor introduced several new dedicated pages:
  • /projects/:projectId/dashboard - Project-specific dashboard with metrics
  • /projects/:projectId/agents - Project-specific agent management
  • /projects/:projectId/github-issues - GitHub issue viewing and syncing
  • /projects/:projectId/worktrees - Git worktree management
  • /projects/:projectId/settings - Full-page project settings (replaced dialog/drawer)
  • /projects/:projectId/terminals - PTY terminal sessions in worktree directories

title: Client overview