T-CREATOR

Cursor が巨大リポジトリで重い時の対処:インデックス最適化と部分学習のコツ

Cursor が巨大リポジトリで重い時の対処:インデックス最適化と部分学習のコツ

巨大なリポジトリで Cursor を使っていると、動作が重くて開発効率が下がってしまった経験はありませんか。特に数万ファイルを含むモノレポや、長年蓄積された大規模プロジェクトでは、Cursor のインデックス処理が追いつかずに、コード補完や解析機能が期待通りに動作しないことがあります。

しかし、適切な設定と最適化を行うことで、これらの問題は大幅に改善できます。本記事では、インデックス最適化と部分学習のテクニックを使って、巨大リポジトリでも Cursor を快適に使う方法をご紹介します。

巨大リポジトリでの Cursor 動作問題

巨大リポジトリで Cursor を使用する際、以下のような問題が発生することがあります。

Cursor は高度な AI 機能を提供するために、プロジェクト全体のコード構造を理解する必要があります。しかし、リポジトリサイズが一定を超えると、この処理がボトルネックとなり、ユーザー体験が著しく悪化します。

以下のような症状が現れた場合、最適化が必要です:

  • Cursor の起動に数分かかる
  • コード補完の反応が極端に遅い
  • ファイル保存時にフリーズする
  • メモリ使用量が異常に高い
  • AI 機能が正常に動作しない

これらの問題を解決するには、Cursor がどのようにリポジトリを処理しているかを理解することが重要です。

mermaidflowchart TD
    repo[巨大リポジトリ] -->|スキャン| cursor[Cursor]
    cursor -->|インデックス作成| index[ファイルインデックス]
    cursor -->|AI学習| ai[コンテキスト学習]
    index -->|重い処理| slow[動作低下]
    ai -->|メモリ消費| memory[メモリ不足]
    slow --> problem[パフォーマンス問題]
    memory --> problem

図解: Cursor が巨大リポジトリを処理する際の問題発生フロー

パフォーマンス低下の主な原因

インデックス処理の負荷

Cursor は効率的なコード解析のために、プロジェクト内のすべてのファイルをインデックス化します。このプロセスでは、以下の処理が実行されます。

javascript// Cursorが内部で行うインデックス処理の概念
const indexingProcess = {
  fileScanning: 'プロジェクト内の全ファイルを走査',
  syntaxAnalysis: '各ファイルの構文解析',
  dependencyMapping: 'ファイル間の依存関係マッピング',
  symbolExtraction: 'クラス、関数、変数の抽出',
};

巨大リポジトリでは、このインデックス処理が膨大な時間とリソースを消費します。特に以下のようなファイルが多数存在する場合、処理負荷は指数関数的に増加します:

ファイル種類処理負荷備考
TypeScript/JavaScript複雑な構文解析が必要
node_modules極高大量の依存関係ファイル
ビルド成果物不要だが処理される
画像・動画バイナリファイルは軽微
ログファイルサイズが大きい場合は負荷大

メモリ消費量の増大

Cursor は学習したコンテキスト情報をメモリ上に保持します。巨大リポジトリではこのメモリ使用量が急激に増加し、システム全体のパフォーマンスに影響を与えます。

typescript// メモリ使用量の概算
interface MemoryUsage {
  indexData: number; // インデックスデータ: ~100MB-2GB
  aiContext: number; // AI学習コンテキスト: ~500MB-5GB
  fileCache: number; // ファイルキャッシュ: ~50MB-500MB
  totalEstimate: number; // 合計推定値
}

const calculateMemoryUsage = (
  fileCount: number
): MemoryUsage => {
  return {
    indexData: fileCount * 0.1, // ファイル数 × 100KB
    aiContext: fileCount * 0.5, // ファイル数 × 500KB
    fileCache: fileCount * 0.05, // ファイル数 × 50KB
    totalEstimate: fileCount * 0.65, // 合計
  };
};

メモリ不足により以下の問題が発生します:

  • スワップファイルの使用によるディスク I/O 増加
  • ガベージコレクションの頻発
  • 他のアプリケーションの動作不良
  • システム全体の応答性低下

ファイル数による制限

多くのファイルシステムや OS には、同時に開けるファイル数に制限があります。Cursor がこの制限に達すると、正常な動作ができなくなります。

bash# ファイル制限の確認方法(macOS/Linux)
ulimit -n  # 現在の制限値を表示
# 通常は1024または8192

特に以下のような構成のプロジェクトでは制限に達しやすくなります:

  • マイクロサービス構成のモノレポ
  • 多言語対応プロジェクト
  • 大量のテストファイルを含むプロジェクト
  • 複数のフレームワークを併用するプロジェクト
mermaidgraph LR
    files[ファイル数増加] --> limit[OS制限到達]
    limit --> error[ファイルオープンエラー]
    error --> failure[機能停止]

    files --> memory[メモリ使用量増加]
    memory --> swap[スワップ使用]
    swap --> slow[動作低下]

図で理解できる要点:

  • ファイル数増加が複数の制限を引き起こす
  • OS 制限とメモリ制限は独立した問題
  • 最終的にはパフォーマンス低下に収束する

インデックス最適化戦略

.cursorignore ファイルの効果的な設定

.cursorignoreファイルは、Cursor のインデックス対象から特定のファイルやディレクトリを除外するための設定ファイルです。適切に設定することで、処理時間とメモリ使用量を大幅に削減できます。

プロジェクトルートに.cursorignoreファイルを作成し、以下のような設定を行います:

text# Node.js プロジェクトの基本設定
node_modules/
dist/
build/
.next/
.nuxt/

# ログファイルとキャッシュ
*.log
logs/
.cache/
.tmp/
temp/

# ビルド成果物
*.min.js
*.min.css
*.bundle.js
coverage/
.nyc_output/

# IDEと開発ツール
.vscode/
.idea/
*.swp
*.swo
.DS_Store

# バージョン管理
.git/
.svn/
.hg/

# 環境固有ファイル
.env
.env.local
.env.production

# 大きなデータファイル
*.sql
*.dump
*.backup
data/
uploads/

効果的な除外パターンの選び方:

typescriptinterface IgnoreStrategy {
  priority: 'high' | 'medium' | 'low';
  pattern: string;
  reason: string;
  estimatedSavings: string;
}

const ignorePatterns: IgnoreStrategy[] = [
  {
    priority: 'high',
    pattern: 'node_modules/',
    reason: '大量の外部依存関係',
    estimatedSavings: '80-90%のファイル数削減',
  },
  {
    priority: 'high',
    pattern: 'dist/',
    reason: 'ビルド成果物(自動生成)',
    estimatedSavings: '10-20%のファイル数削減',
  },
  {
    priority: 'medium',
    pattern: '*.log',
    reason: 'ログファイル(大容量)',
    estimatedSavings: 'メモリ使用量20-30%削減',
  },
];

段階的インデックス構築

大きなプロジェクトでは、一度にすべてをインデックス化するのではなく、段階的にインデックスを構築することが効果的です。

Cursor の設定で段階的インデックスを有効にする方法:

json{
  "cursor.indexing.mode": "incremental",
  "cursor.indexing.batchSize": 100,
  "cursor.indexing.delay": 50,
  "cursor.indexing.priority": [
    "src/",
    "lib/",
    "components/",
    "utils/"
  ]
}

段階的インデックス構築の実装例:

javascript// インデックス優先度の設定
const indexingPriority = {
  phase1: ['src/components/', 'src/utils/'], // 最優先
  phase2: ['src/pages/', 'src/hooks/'], // 次優先
  phase3: ['tests/', 'docs/'], // 最後
  excluded: ['node_modules/', 'dist/', '.git/'], // 除外
};

// 段階的処理の実装
const processIndexingPhases = async () => {
  for (const [phase, directories] of Object.entries(
    indexingPriority
  )) {
    if (phase === 'excluded') continue;

    console.log(`Starting ${phase}...`);
    await indexDirectories(directories);
    await new Promise((resolve) =>
      setTimeout(resolve, 1000)
    ); // 1秒待機
  }
};

この方法により、重要なファイルから優先的にインデックス化され、開発中に必要な機能をより早く利用できます。

キャッシュ最適化

Cursor は効率化のためにインデックス情報をキャッシュします。このキャッシュを適切に管理することで、起動時間とメモリ使用量を最適化できます。

キャッシュ設定の最適化:

json{
  "cursor.cache.enabled": true,
  "cursor.cache.maxSize": "2GB",
  "cursor.cache.ttl": 3600,
  "cursor.cache.compression": true,
  "cursor.cache.strategy": "lru"
}

キャッシュ管理スクリプトの例:

bash#!/bin/bash
# キャッシュ最適化スクリプト

CACHE_DIR="$HOME/.cursor/cache"
MAX_CACHE_SIZE="2G"

# キャッシュサイズの確認
current_size=$(du -sh "$CACHE_DIR" | cut -f1)
echo "Current cache size: $current_size"

# 古いキャッシュファイルの削除(7日以上古い)
find "$CACHE_DIR" -type f -mtime +7 -delete

# キャッシュサイズが上限を超えている場合の処理
if [[ $(du -s "$CACHE_DIR" | cut -f1) -gt $(numfmt --from=iec "${MAX_CACHE_SIZE}") ]]; then
    echo "Cache size exceeded limit. Cleaning up..."
    # 最も古いファイルから削除
    find "$CACHE_DIR" -type f -print0 | xargs -0 ls -lt | tail -n +100 | cut -d' ' -f9- | xargs rm -f
fi

定期的なキャッシュメンテナンス:

typescript// キャッシュメンテナンスの自動化
interface CacheMaintenanceConfig {
  interval: number; // メンテナンス間隔(分)
  maxAge: number; // 最大保持期間(時間)
  maxSize: string; // 最大サイズ
  compressionLevel: number; // 圧縮レベル(1-9)
}

const cacheConfig: CacheMaintenanceConfig = {
  interval: 60, // 1時間ごと
  maxAge: 24, // 24時間
  maxSize: '2GB',
  compressionLevel: 6,
};

const scheduleCacheMaintenance = (
  config: CacheMaintenanceConfig
) => {
  setInterval(async () => {
    await cleanupOldCache(config.maxAge);
    await compressCache(config.compressionLevel);
    await enforceMaxSize(config.maxSize);
  }, config.interval * 60 * 1000);
};

部分学習による効率化

ワークスペース分割のアプローチ

巨大リポジトリを機能別に分割し、必要な部分のみを Cursor に学習させることで、パフォーマンスを大幅に改善できます。

効果的なワークスペース分割の戦略:

typescript// ワークスペース分割の設定例
interface WorkspaceConfig {
  name: string;
  paths: string[];
  dependencies: string[];
  priority: number;
}

const workspaceConfigs: WorkspaceConfig[] = [
  {
    name: 'frontend',
    paths: ['src/components/', 'src/pages/', 'src/hooks/'],
    dependencies: ['shared/types/', 'shared/utils/'],
    priority: 1,
  },
  {
    name: 'backend',
    paths: ['server/', 'api/', 'database/'],
    dependencies: ['shared/types/', 'shared/constants/'],
    priority: 2,
  },
  {
    name: 'shared',
    paths: ['shared/', 'types/', 'constants/'],
    dependencies: [],
    priority: 3,
  },
];

VS Code のワークスペース設定(.vscode​/​workspace.code-workspace):

json{
  "folders": [
    {
      "name": "Frontend",
      "path": "./src"
    },
    {
      "name": "Backend",
      "path": "./server"
    },
    {
      "name": "Shared",
      "path": "./shared"
    }
  ],
  "settings": {
    "cursor.workspace.focus": "Frontend",
    "cursor.learning.scope": ["Frontend", "Shared"],
    "files.exclude": {
      "**/node_modules": true,
      "**/dist": true,
      "server/**": true
    }
  }
}

動的ワークスペース切り替えスクリプト:

bash#!/bin/bash
# ワークスペース切り替えスクリプト

WORKSPACE_DIR=".vscode/workspaces"
CURRENT_WORKSPACE="$1"

if [ -z "$CURRENT_WORKSPACE" ]; then
    echo "使用方法: switch-workspace.sh [frontend|backend|full]"
    exit 1
fi

# ワークスペース設定の適用
case "$CURRENT_WORKSPACE" in
    frontend)
        cp "$WORKSPACE_DIR/frontend.code-workspace" ".vscode/workspace.code-workspace"
        echo "フロントエンド開発環境に切り替えました"
        ;;
    backend)
        cp "$WORKSPACE_DIR/backend.code-workspace" ".vscode/workspace.code-workspace"
        echo "バックエンド開発環境に切り替えました"
        ;;
    full)
        cp "$WORKSPACE_DIR/full.code-workspace" ".vscode/workspace.code-workspace"
        echo "全体開発環境に切り替えました"
        ;;
    *)
        echo "不正なワークスペース名: $CURRENT_WORKSPACE"
        exit 1
        ;;
esac

必要最小限のコンテキスト設定

Cursor の学習コンテキストを必要最小限に制限することで、メモリ使用量を削減し、応答速度を向上させます。

コンテキスト制御の設定:

json{
  "cursor.context.maxFiles": 50,
  "cursor.context.maxSize": "10MB",
  "cursor.context.strategy": "relevant-only",
  "cursor.context.excludePatterns": [
    "**/*.min.js",
    "**/*.bundle.js",
    "**/dist/**",
    "**/node_modules/**"
  ],
  "cursor.context.includePatterns": [
    "src/**/*.{ts,tsx,js,jsx}",
    "types/**/*.ts",
    "utils/**/*.ts"
  ]
}

動的コンテキスト調整の実装:

typescript// コンテキスト管理クラス
class ContextManager {
  private maxContextSize: number;
  private currentContext: Set<string>;
  private relevanceScores: Map<string, number>;

  constructor(maxSize: number = 50) {
    this.maxContextSize = maxSize;
    this.currentContext = new Set();
    this.relevanceScores = new Map();
  }

  // 関連度に基づいてファイルを評価
  calculateRelevance(
    filePath: string,
    currentFile: string
  ): number {
    let score = 0;

    // 同じディレクトリのファイル
    if (
      path.dirname(filePath) === path.dirname(currentFile)
    ) {
      score += 10;
    }

    // インポート関係のあるファイル
    if (this.hasImportRelation(filePath, currentFile)) {
      score += 15;
    }

    // 最近編集されたファイル
    const lastModified = fs.statSync(filePath).mtime;
    const daysSinceModified =
      (Date.now() - lastModified.getTime()) /
      (1000 * 60 * 60 * 24);
    score += Math.max(0, 5 - daysSinceModified);

    return score;
  }

  // コンテキストの最適化
  optimizeContext(currentFile: string): void {
    const candidates = this.getAllCandidateFiles();

    // 関連度の計算
    candidates.forEach((file) => {
      const relevance = this.calculateRelevance(
        file,
        currentFile
      );
      this.relevanceScores.set(file, relevance);
    });

    // 上位ファイルのみを選択
    const sortedFiles = Array.from(
      this.relevanceScores.entries()
    )
      .sort(([, a], [, b]) => b - a)
      .slice(0, this.maxContextSize)
      .map(([file]) => file);

    this.currentContext = new Set(sortedFiles);
  }
}

プロジェクト構造に応じた学習範囲調整

プロジェクトの構造を分析し、最適な学習範囲を自動で調整する機能を実装します。

プロジェクト構造分析:

typescript// プロジェクト構造の分析
interface ProjectStructure {
  type: 'monorepo' | 'single-package' | 'micro-frontend';
  packages: PackageInfo[];
  dependencies: DependencyGraph;
  hotspots: string[]; // よく変更されるファイル
}

interface PackageInfo {
  name: string;
  path: string;
  size: number;
  lastModified: Date;
  importance: number;
}

class ProjectAnalyzer {
  async analyzeStructure(
    rootPath: string
  ): Promise<ProjectStructure> {
    const packages = await this.discoverPackages(rootPath);
    const dependencies = await this.buildDependencyGraph(
      packages
    );
    const hotspots = await this.identifyHotspots(rootPath);

    return {
      type: this.inferProjectType(packages),
      packages,
      dependencies,
      hotspots,
    };
  }

  private async discoverPackages(
    rootPath: string
  ): Promise<PackageInfo[]> {
    const packages: PackageInfo[] = [];
    const packageFiles = await glob('**/package.json', {
      cwd: rootPath,
    });

    for (const packageFile of packageFiles) {
      const packagePath = path.dirname(packageFile);
      const stats = await fs.stat(
        path.join(rootPath, packagePath)
      );
      const packageJson = JSON.parse(
        await fs.readFile(
          path.join(rootPath, packageFile),
          'utf-8'
        )
      );

      packages.push({
        name:
          packageJson.name || path.basename(packagePath),
        path: packagePath,
        size: await this.calculateDirectorySize(
          path.join(rootPath, packagePath)
        ),
        lastModified: stats.mtime,
        importance: this.calculateImportance(
          packageJson,
          packages
        ),
      });
    }

    return packages;
  }
}

学習範囲の自動調整:

typescript// 学習範囲の最適化
class LearningOptimizer {
  private projectStructure: ProjectStructure;
  private memoryLimit: number;

  constructor(
    structure: ProjectStructure,
    memoryLimitMB: number = 2048
  ) {
    this.projectStructure = structure;
    this.memoryLimit = memoryLimitMB * 1024 * 1024; // MBからバイトに変換
  }

  optimizeLearningScope(): string[] {
    const packages = this.projectStructure.packages.sort(
      (a, b) => b.importance - a.importance
    );

    const selectedPaths: string[] = [];
    let currentMemoryUsage = 0;

    for (const pkg of packages) {
      const estimatedMemory = this.estimateMemoryUsage(pkg);

      if (
        currentMemoryUsage + estimatedMemory <=
        this.memoryLimit
      ) {
        selectedPaths.push(pkg.path);
        currentMemoryUsage += estimatedMemory;
      } else {
        break;
      }
    }

    // 必須パッケージの追加
    this.addEssentialPaths(selectedPaths);

    return selectedPaths;
  }

  private estimateMemoryUsage(pkg: PackageInfo): number {
    // パッケージサイズベースのメモリ使用量推定
    return pkg.size * 0.3; // 経験的な係数
  }

  private addEssentialPaths(paths: string[]): void {
    const essentialPaths = [
      'types/',
      'shared/',
      'utils/',
      'constants/',
    ];

    essentialPaths.forEach((path) => {
      if (!paths.includes(path) && fs.existsSync(path)) {
        paths.push(path);
      }
    });
  }
}
mermaidgraph TD
    project[プロジェクト分析] --> structure[構造把握]
    structure --> packages[パッケージ発見]
    structure --> deps[依存関係分析]
    structure --> hotspots[ホットスポット特定]

    packages --> importance[重要度計算]
    deps --> importance
    hotspots --> importance

    importance --> selection[学習範囲選択]
    selection --> memory[メモリ制限チェック]
    memory --> optimize[最適化実行]

図で理解できる要点:

  • プロジェクト分析から最適化まで段階的に処理
  • 複数の指標を組み合わせて重要度を算出
  • メモリ制限を考慮した現実的な選択

実践的な設定例とコード

設定ファイルの具体例

実際のプロジェクトで使用できる包括的な設定例をご紹介します。

Cursor 設定ファイル(.vscode​/​settings.json):

json{
  "cursor.general.enableLogging": true,
  "cursor.performance.optimizeForLargeFiles": true,
  "cursor.indexing.excludePatterns": [
    "**/node_modules/**",
    "**/dist/**",
    "**/build/**",
    "**/.git/**",
    "**/*.log",
    "**/coverage/**",
    "**/.nyc_output/**"
  ],
  "cursor.indexing.includePatterns": [
    "src/**/*.{ts,tsx,js,jsx,vue}",
    "lib/**/*.{ts,js}",
    "types/**/*.ts",
    "utils/**/*.{ts,js}",
    "components/**/*.{ts,tsx,vue}",
    "pages/**/*.{ts,tsx,js,jsx}",
    "api/**/*.{ts,js}",
    "server/**/*.{ts,js}",
    "tests/**/*.{ts,js,spec.ts,test.ts}"
  ],
  "cursor.context.maxTokens": 4000,
  "cursor.context.maxFiles": 30,
  "cursor.memory.maxUsageMB": 2048,
  "cursor.cache.enabled": true,
  "cursor.cache.maxSizeMB": 512,
  "cursor.ai.model": "gpt-4",
  "cursor.ai.temperature": 0.2,
  "files.watcherExclude": {
    "**/node_modules/**": true,
    "**/dist/**": true,
    "**/build/**": true,
    "**/.git/**": true,
    "**/logs/**": true,
    "**/tmp/**": true,
    "**/temp/**": true
  },
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/build": true,
    "**/.git": true,
    "**/coverage": true,
    "**/*.min.js": true,
    "**/*.bundle.js": true
  },
  "files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true,
    "**/node_modules": true,
    "**/dist": true,
    "**/build": true,
    "**/*.log": true
  }
}

プロジェクト固有の設定(.cursorrc):

yaml# Cursor設定ファイル
version: '1.0'

# インデックス設定
indexing:
  mode: 'incremental'
  batchSize: 50
  delay: 100
  priority:
    - 'src/'
    - 'lib/'
    - 'types/'
    - 'utils/'
  exclude:
    - 'node_modules/'
    - 'dist/'
    - 'build/'
    - '.git/'
    - '*.log'
    - 'coverage/'

# メモリ管理
memory:
  maxUsageMB: 2048
  garbageCollection: 'aggressive'
  cacheStrategy: 'lru'

# AI設定
ai:
  model: 'gpt-4'
  temperature: 0.2
  maxTokens: 4000
  contextStrategy: 'relevant-files'

# パフォーマンス設定
performance:
  enableFileWatching: true
  debounceMs: 300
  maxConcurrentRequests: 3
  timeoutMs: 30000

# プロジェクト構造
structure:
  type: 'monorepo'
  packages:
    - name: 'frontend'
      path: 'packages/frontend'
      priority: 1
    - name: 'backend'
      path: 'packages/backend'
      priority: 2
    - name: 'shared'
      path: 'packages/shared'
      priority: 3

環境別設定の管理:

typescript// 環境別設定管理
interface EnvironmentConfig {
  development: CursorConfig;
  production: CursorConfig;
  testing: CursorConfig;
}

interface CursorConfig {
  memory: {
    maxUsageMB: number;
    cacheStrategy: string;
  };
  indexing: {
    mode: string;
    batchSize: number;
    priority: string[];
  };
  ai: {
    model: string;
    temperature: number;
  };
}

const environmentConfigs: EnvironmentConfig = {
  development: {
    memory: {
      maxUsageMB: 4096, // 開発時は大きめ
      cacheStrategy: 'aggressive',
    },
    indexing: {
      mode: 'full',
      batchSize: 100,
      priority: ['src/', 'tests/', 'docs/'],
    },
    ai: {
      model: 'gpt-4',
      temperature: 0.3,
    },
  },
  production: {
    memory: {
      maxUsageMB: 1024, // 本番は制限
      cacheStrategy: 'conservative',
    },
    indexing: {
      mode: 'incremental',
      batchSize: 50,
      priority: ['src/'],
    },
    ai: {
      model: 'gpt-3.5-turbo',
      temperature: 0.1,
    },
  },
  testing: {
    memory: {
      maxUsageMB: 512, // テスト時は最小限
      cacheStrategy: 'minimal',
    },
    indexing: {
      mode: 'minimal',
      batchSize: 25,
      priority: ['tests/'],
    },
    ai: {
      model: 'gpt-3.5-turbo',
      temperature: 0.0,
    },
  },
};

パフォーマンス測定方法

Cursor のパフォーマンスを定量的に測定し、最適化の効果を確認する方法をご紹介します。

パフォーマンス測定スクリプト:

javascript// パフォーマンス測定ツール
class CursorPerformanceMonitor {
  constructor() {
    this.metrics = {
      startupTime: 0,
      indexingTime: 0,
      memoryUsage: [],
      responseTime: [],
      errorCount: 0,
    };
    this.startTime = Date.now();
  }

  // 起動時間の測定
  measureStartupTime() {
    const startupTime = Date.now() - this.startTime;
    this.metrics.startupTime = startupTime;
    console.log(`Cursor起動時間: ${startupTime}ms`);
    return startupTime;
  }

  // メモリ使用量の監視
  monitorMemoryUsage() {
    const measureMemory = () => {
      if (process.memoryUsage) {
        const usage = process.memoryUsage();
        this.metrics.memoryUsage.push({
          timestamp: Date.now(),
          heapUsed: usage.heapUsed,
          heapTotal: usage.heapTotal,
          external: usage.external,
        });
      }
    };

    // 5秒ごとにメモリ使用量を記録
    setInterval(measureMemory, 5000);
    measureMemory(); // 初回実行
  }

  // レスポンス時間の測定
  async measureResponseTime(operation, ...args) {
    const startTime = performance.now();
    try {
      const result = await operation(...args);
      const endTime = performance.now();
      const responseTime = endTime - startTime;

      this.metrics.responseTime.push({
        operation: operation.name,
        time: responseTime,
        timestamp: Date.now(),
      });

      console.log(
        `${operation.name}: ${responseTime.toFixed(2)}ms`
      );
      return result;
    } catch (error) {
      this.metrics.errorCount++;
      console.error(`Error in ${operation.name}:`, error);
      throw error;
    }
  }

  // レポートの生成
  generateReport() {
    const avgResponseTime =
      this.metrics.responseTime.length > 0
        ? this.metrics.responseTime.reduce(
            (sum, item) => sum + item.time,
            0
          ) / this.metrics.responseTime.length
        : 0;

    const avgMemoryUsage =
      this.metrics.memoryUsage.length > 0
        ? this.metrics.memoryUsage.reduce(
            (sum, item) => sum + item.heapUsed,
            0
          ) / this.metrics.memoryUsage.length
        : 0;

    return {
      startupTime: this.metrics.startupTime,
      averageResponseTime: avgResponseTime,
      averageMemoryUsage: Math.round(
        avgMemoryUsage / 1024 / 1024
      ), // MB
      totalErrors: this.metrics.errorCount,
      memoryPeakUsage:
        Math.max(
          ...this.metrics.memoryUsage.map((m) => m.heapUsed)
        ) /
        1024 /
        1024,
      responseTimeP95: this.calculatePercentile(
        this.metrics.responseTime.map((r) => r.time),
        95
      ),
    };
  }

  calculatePercentile(values, percentile) {
    const sorted = [...values].sort((a, b) => a - b);
    const index =
      Math.ceil((percentile / 100) * sorted.length) - 1;
    return sorted[index] || 0;
  }
}

ベンチマークテストの実装:

bash#!/bin/bash
# Cursorパフォーマンステストスクリプト

echo "Cursorパフォーマンステストを開始します..."

# テスト環境の情報収集
echo "=== システム情報 ==="
echo "OS: $(uname -s)"
echo "メモリ: $(free -h | grep Mem | awk '{print $2}' 2>/dev/null || echo 'N/A')"
echo "CPU: $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 'N/A') cores"

# プロジェクト情報
echo "=== プロジェクト情報 ==="
file_count=$(find . -type f | wc -l)
js_file_count=$(find . -name "*.js" -o -name "*.ts" -o -name "*.jsx" -o -name "*.tsx" | wc -l)
echo "総ファイル数: $file_count"
echo "JS/TSファイル数: $js_file_count"

# Cursorの起動時間測定
echo "=== 起動時間測定 ==="
start_time=$(date +%s%N)
code . --wait
end_time=$(date +%s%N)
startup_time=$(((end_time - start_time) / 1000000))
echo "起動時間: ${startup_time}ms"

# インデックス処理時間の測定
echo "=== インデックス処理時間測定 ==="
# インデックスキャッシュを削除
rm -rf ~/.cursor/cache/*
start_time=$(date +%s%N)
# インデックス再構築をトリガー
curl -X POST http://localhost:23432/api/reindex 2>/dev/null || echo "インデックス再構築API呼び出し失敗"
sleep 5
end_time=$(date +%s%N)
index_time=$(((end_time - start_time) / 1000000))
echo "インデックス処理時間: ${index_time}ms"

# メモリ使用量の測定
echo "=== メモリ使用量測定 ==="
cursor_pid=$(pgrep -f cursor | head -1)
if [ ! -z "$cursor_pid" ]; then
    memory_usage=$(ps -p $cursor_pid -o rss= 2>/dev/null)
    if [ ! -z "$memory_usage" ]; then
        echo "メモリ使用量: $((memory_usage / 1024))MB"
    fi
fi

# 結果をファイルに保存
cat > performance_report.json <<EOF
{
  "timestamp": "$(date -Iseconds)",
  "system": {
    "os": "$(uname -s)",
    "memory": "$(free -h | grep Mem | awk '{print $2}' 2>/dev/null || echo 'N/A')",
    "cpu_cores": $(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null || echo 0)
  },
  "project": {
    "total_files": $file_count,
    "js_ts_files": $js_file_count
  },
  "performance": {
    "startup_time_ms": $startup_time,
    "indexing_time_ms": $index_time,
    "memory_usage_mb": $((memory_usage / 1024))
  }
}
EOF

echo "パフォーマンステスト完了。結果は performance_report.json に保存されました。"

継続的なパフォーマンス監視:

typescript// 継続的監視システム
class ContinuousMonitor {
  private metrics: Map<string, number[]> = new Map();
  private thresholds = {
    responseTime: 1000, // 1秒
    memoryUsage: 2048, // 2GB
    errorRate: 0.05, // 5%
  };

  startMonitoring() {
    // 定期的なヘルスチェック
    setInterval(() => {
      this.collectMetrics();
      this.checkThresholds();
    }, 60000); // 1分ごと

    // プロセス終了時のレポート生成
    process.on('exit', () => {
      this.generateFinalReport();
    });
  }

  private collectMetrics() {
    const now = Date.now();
    const memUsage = process.memoryUsage();

    this.addMetric(
      'memory_heap_used',
      memUsage.heapUsed / 1024 / 1024
    );
    this.addMetric(
      'memory_heap_total',
      memUsage.heapTotal / 1024 / 1024
    );
    this.addMetric('timestamp', now);
  }

  private addMetric(key: string, value: number) {
    if (!this.metrics.has(key)) {
      this.metrics.set(key, []);
    }
    const values = this.metrics.get(key)!;
    values.push(value);

    // 最新100件のみ保持
    if (values.length > 100) {
      values.shift();
    }
  }

  private checkThresholds() {
    const currentMemory =
      this.metrics.get('memory_heap_used')?.slice(-1)[0] ||
      0;

    if (currentMemory > this.thresholds.memoryUsage) {
      console.warn(
        `⚠️ メモリ使用量が閾値を超えました: ${currentMemory.toFixed(
          2
        )}MB`
      );
      this.suggestOptimizations();
    }
  }

  private suggestOptimizations() {
    console.log('🔧 最適化提案:');
    console.log('1. .cursorignoreファイルの見直し');
    console.log('2. キャッシュのクリア');
    console.log('3. ワークスペースの分割');
    console.log('4. 不要なファイルの除外');
  }
}

運用時の注意点

実際に Cursor を運用する際の重要なポイントと、よくある問題の対処法をまとめました。

定期メンテナンススクリプト:

bash#!/bin/bash
# Cursor定期メンテナンススクリプト

MAINTENANCE_LOG="cursor_maintenance.log"
BACKUP_DIR="$HOME/.cursor/backups"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$MAINTENANCE_LOG"
}

# バックアップの作成
create_backup() {
    log "設定バックアップを作成中..."
    mkdir -p "$BACKUP_DIR"

    # 設定ファイルのバックアップ
    if [ -f ".vscode/settings.json" ]; then
        cp ".vscode/settings.json" "$BACKUP_DIR/settings_$(date +%Y%m%d).json"
    fi

    if [ -f ".cursorignore" ]; then
        cp ".cursorignore" "$BACKUP_DIR/cursorignore_$(date +%Y%m%d)"
    fi

    log "バックアップ完了"
}

# キャッシュのクリーンアップ
cleanup_cache() {
    log "キャッシュクリーンアップを開始..."

    # 古いキャッシュファイルの削除(7日以上)
    find "$HOME/.cursor/cache" -type f -mtime +7 -delete 2>/dev/null

    # ログファイルの削除(30日以上)
    find "$HOME/.cursor/logs" -name "*.log" -mtime +30 -delete 2>/dev/null

    log "キャッシュクリーンアップ完了"
}

# パフォーマンスチェック
performance_check() {
    log "パフォーマンスチェックを実行中..."

    # ディスク使用量チェック
    cache_size=$(du -sh "$HOME/.cursor/cache" 2>/dev/null | cut -f1)
    log "キャッシュサイズ: $cache_size"

    # ファイル数チェック
    file_count=$(find . -type f | wc -l)
    excluded_count=$(find . -type f -path "*/node_modules/*" -o -path "*/dist/*" -o -path "*/.git/*" | wc -l)
    indexed_count=$((file_count - excluded_count))

    log "総ファイル数: $file_count"
    log "除外ファイル数: $excluded_count"
    log "インデックス対象: $indexed_count"

    # 推奨事項
    if [ "$indexed_count" -gt 10000 ]; then
        log "⚠️ インデックス対象ファイルが多すぎます($indexed_count > 10000)"
        log "💡 .cursorignoreファイルの見直しを推奨"
    fi
}

# 設定の検証
validate_config() {
    log "設定ファイルの検証中..."

    # .cursorignoreの存在確認
    if [ ! -f ".cursorignore" ]; then
        log "⚠️ .cursorignoreファイルが存在しません"
        log "💡 .cursorignoreファイルの作成を推奨"
    fi

    # settings.jsonの検証
    if [ -f ".vscode/settings.json" ]; then
        if ! python3 -c "import json; json.load(open('.vscode/settings.json'))" 2>/dev/null; then
            log "❌ settings.jsonの構文エラーを検出"
        else
            log "✅ settings.json構文OK"
        fi
    fi
}

# メイン処理
main() {
    log "Cursor定期メンテナンス開始"

    create_backup
    cleanup_cache
    performance_check
    validate_config

    log "Cursor定期メンテナンス完了"
}

# エラーハンドリング
trap 'log "❌ メンテナンス中にエラーが発生しました"; exit 1' ERR

main "$@"

運用チェックリスト:

typescript// 運用チェックリストの自動実行
interface ChecklistItem {
  name: string;
  check: () => Promise<boolean>;
  fix?: () => Promise<void>;
  severity: 'low' | 'medium' | 'high';
}

class OperationChecklist {
  private checklist: ChecklistItem[] = [
    {
      name: 'メモリ使用量チェック',
      check: async () => {
        const usage = process.memoryUsage();
        return usage.heapUsed < 2 * 1024 * 1024 * 1024; // 2GB未満
      },
      fix: async () => {
        console.log('キャッシュをクリアしています...');
        // キャッシュクリア処理
      },
      severity: 'high',
    },
    {
      name: 'インデックス対象ファイル数チェック',
      check: async () => {
        const fileCount = await this.countIndexedFiles();
        return fileCount < 10000;
      },
      fix: async () => {
        console.log(
          '.cursorignoreファイルの最適化を提案します'
        );
        await this.suggestIgnorePatterns();
      },
      severity: 'medium',
    },
    {
      name: 'キャッシュサイズチェック',
      check: async () => {
        const cacheSize = await this.getCacheSize();
        return cacheSize < 1024 * 1024 * 1024; // 1GB未満
      },
      fix: async () => {
        await this.cleanupCache();
      },
      severity: 'medium',
    },
    {
      name: '設定ファイル構文チェック',
      check: async () => {
        return await this.validateConfigFiles();
      },
      fix: async () => {
        console.log('設定ファイルの修正を提案します');
        await this.fixConfigSyntax();
      },
      severity: 'high',
    },
  ];

  async runChecklist(): Promise<void> {
    console.log('🔍 運用チェックリストを実行中...\n');

    const results = [];

    for (const item of this.checklist) {
      console.log(`チェック中: ${item.name}`);

      try {
        const passed = await item.check();

        if (passed) {
          console.log(`✅ ${item.name}: OK`);
          results.push({ name: item.name, status: 'pass' });
        } else {
          console.log(
            `❌ ${item.name}: NG (重要度: ${item.severity})`
          );
          results.push({
            name: item.name,
            status: 'fail',
            severity: item.severity,
          });

          if (item.fix) {
            console.log(`🔧 自動修正を実行中...`);
            await item.fix();
          }
        }
      } catch (error) {
        console.log(
          `⚠️ ${item.name}: エラー - ${error.message}`
        );
        results.push({
          name: item.name,
          status: 'error',
          error: error.message,
        });
      }

      console.log('');
    }

    this.generateReport(results);
  }

  private generateReport(results: any[]): void {
    const failedItems = results.filter(
      (r) => r.status === 'fail'
    );
    const errorItems = results.filter(
      (r) => r.status === 'error'
    );

    console.log('📊 チェック結果サマリー');
    console.log(
      `✅ 成功: ${
        results.filter((r) => r.status === 'pass').length
      }`
    );
    console.log(`❌ 失敗: ${failedItems.length}`);
    console.log(`⚠️ エラー: ${errorItems.length}`);

    if (failedItems.length > 0) {
      console.log('\n🔧 推奨アクション:');
      failedItems.forEach((item) => {
        console.log(
          `- ${item.name} (重要度: ${item.severity})`
        );
      });
    }
  }
}

トラブルシューティングガイド:

問題症状対処法
起動が遅いCursor 起動に 30 秒以上.cursorignore の見直し、キャッシュクリア
メモリ不足システムが重いワークスペース分割、メモリ制限設定
インデックスエラーファイル認識しないインデックス再構築、設定ファイル確認
AI 応答が遅い補完に 5 秒以上コンテキストサイズ削減、モデル変更
ファイル監視エラー変更が反映されないwatcherExclude 設定、OS 制限確認
mermaidflowchart TD
    problem[問題発生] --> diagnose[診断実行]
    diagnose --> memory{メモリ関連?}
    diagnose --> performance{パフォーマンス関連?}
    diagnose --> config{設定関連?}

    memory -->|Yes| cleanup[キャッシュクリア]
    memory -->|Yes| split[ワークスペース分割]

    performance -->|Yes| ignore[.cursorignore最適化]
    performance -->|Yes| index[インデックス再構築]

    config -->|Yes| validate[設定検証]
    config -->|Yes| backup[バックアップから復旧]

    cleanup --> verify[動作確認]
    split --> verify
    ignore --> verify
    index --> verify
    validate --> verify
    backup --> verify

    verify -->|OK| done[解決]
    verify -->|NG| escalate[エスカレーション]

図で理解できる要点:

  • 問題の種類に応じた適切な対処法を選択
  • 各対処法実行後は必ず動作確認を実施
  • 解決しない場合はエスカレーション手順へ

まとめ

巨大リポジトリで Cursor を快適に使用するためには、以下の最適化アプローチが効果的です。

インデックス最適化では、.cursorignoreによる適切な除外設定、段階的インデックス構築、キャッシュ管理が重要です。特にnode_modulesdistフォルダの除外により、80-90%のファイル数削減が可能になります。

部分学習による効率化では、ワークスペース分割、コンテキスト制限、プロジェクト構造に応じた学習範囲調整により、メモリ使用量を大幅に削減できます。開発フェーズに応じて必要な部分のみを学習対象とすることで、応答速度が向上します。

運用面では、定期的なパフォーマンス測定、設定の見直し、メンテナンススクリプトの自動実行により、長期的に安定した動作を維持できます。

これらの最適化により、数万ファイルを含む巨大リポジトリでも、Cursor の起動時間を数分から数十秒に短縮し、メモリ使用量を半分以下に削減することが可能です。適切な設定と継続的な最適化により、開発効率を大幅に向上させることができるでしょう。

関連リンク