JA Development Guides Local Development - aku11i/phantom GitHub Wiki

ローカル開発

English | 日本語

このガイドでは、開発中のPhantomをローカルで実行する方法について、セットアップ、ワークフロー、一般的なタスクを含めて説明します。

前提条件

ローカル開発を始める前に、以下があることを確認してください:

  • Node.js v22.0.0以上
  • pnpm v10.8.1以上
  • Git(worktreeサポート付き)
  • コードエディター(VS Code推奨)

詳細なインストール手順については、開発セットアップを参照してください。

はじめに

1. クローンとセットアップ

# リポジトリをクローン
git clone https://github.com/aku11i/phantom.git
cd phantom

# 依存関係をインストール
pnpm install

# セットアップを確認
pnpm test

2. ソースから実行

ソース: package.json#L12

# ソースから直接CLIを実行
pnpm start

# 引数付きで実行
pnpm start create my-feature
pnpm start list
pnpm start exec my-feature "npm test"

3. 開発スクリプト

コマンド 説明 使用ケース
pnpm start ソースからCLIを実行 CLIコマンドのテスト
pnpm build プロジェクトをビルド 配布物の作成
pnpm test ユニットテストを実行 変更の検証
pnpm lint コード品質をチェック 問題の発見
pnpm fix 問題を自動修正 コードのクリーンアップ
pnpm typecheck 型をチェック 型エラーの検出
pnpm ready すべてのチェック コミット前の検証

開発ワークフロー

1. 機能開発

# 新しいブランチを作成
git checkout -b feature/new-command

# 変更を加える
code src/cli/handlers/new-command.ts

# 変更をテスト
pnpm start new-command

# テストを実行
pnpm test

# すべてをチェック
pnpm ready

2. テスト駆動開発

# 1. 最初にテストを書く
code src/core/feature/new-feature.test.ts

# 2. テストを実行(失敗するはず)
node --test src/core/feature/new-feature.test.ts

# 3. 機能を実装
code src/core/feature/new-feature.ts

# 4. テストを再度実行(成功するはず)
node --test src/core/feature/new-feature.test.ts

# 5. すべてのテストを実行
pnpm test

3. デバッグワークフロー

# Node.jsインスペクターで実行
node --inspect-brk dist/phantom.js create test

# デバッグ付きでテストを実行
node --inspect --test src/core/worktree/create.test.ts

# VS Codeデバッガーを使用(下記のIDEセットアップを参照)

プロジェクト構造

コードベースのレイアウトを理解する:

src/
├── bin/
│   └── phantom.ts          # エントリーポイント
├── cli/
│   ├── handlers/          # コマンド実装
│   │   ├── create.ts      # Createコマンド
│   │   ├── delete.ts      # Deleteコマンド
│   │   └── ...           # その他のコマンド
│   ├── output.ts         # 出力フォーマット
│   └── errors.ts         # エラーハンドリング
└── core/
    ├── worktree/         # Worktreeロジック
    ├── git/              # Git操作
    ├── process/          # プロセス管理
    └── types/            # 型定義

一般的な開発タスク

新しいコマンドの追加

  1. ハンドラーファイルを作成
// src/cli/handlers/status.ts
import { Result } from "../../core/types/result.js";
import { getWorktreeStatus } from "../../core/worktree/status.js";
import { output } from "../output.js";

export async function statusHandler(args: string[]): Promise<void> {
  const name = args[0];
  
  if (!name) {
    output.error("Usage: phantom status <name>");
    process.exitCode = 1;
    return;
  }
  
  const result = await getWorktreeStatus(name);
  
  if (!result.ok) {
    output.error(result.error.message);
    process.exitCode = 1;
    return;
  }
  
  output.success(`Status: ${result.value.status}`);
}
  1. コアロジックを追加
// src/core/worktree/status.ts
import { Result } from "../types/result.js";
import { GitExecutor } from "../git/executor.js";

export async function getWorktreeStatus(
  name: string
): Promise<Result<WorktreeStatus>> {
  const git = new GitExecutor();
  
  // 実装
  return Result.ok({ status: "clean" });
}
  1. コマンドを接続
// src/bin/phantom.ts
import { statusHandler } from "../cli/handlers/status.js";

// コマンドスイッチ内
case "status":
  await statusHandler(args.slice(1));
  break;
  1. テストを追加
// src/core/worktree/status.test.ts
import { describe, it } from "node:test";
import assert from "node:assert";
import { getWorktreeStatus } from "./status.js";

describe("getWorktreeStatus", () => {
  it("should return clean status", async () => {
    const result = await getWorktreeStatus("test");
    assert.strictEqual(result.ok, true);
  });
});

既存コマンドの変更

  1. 現在の動作を理解
# 既存のコードを読む
code src/cli/handlers/create.ts
code src/core/worktree/create.ts

# 既存のテストを確認
code src/core/worktree/create.test.ts

# 現在の実装を実行
pnpm start create test-phantom
  1. 変更を加える
// createコマンドに新しいオプションを追加
export async function createHandler(args: string[]): Promise<void> {
  const [name, branch, customPath] = args;
  
  // カスタムパスサポートを追加
  const result = await createWorktree(name, branch, { customPath });
  // ...
}
  1. テストを更新
it("should support custom path option", async () => {
  const result = await createWorktree("test", "main", {
    customPath: "/custom/location"
  });
  
  assert.strictEqual(result.ok, true);
  if (result.ok) {
    assert.strictEqual(result.value.path, "/custom/location/test");
  }
});

Git操作での作業

  1. Gitモジュールの理解
// src/core/git/executor.ts
import { spawn } from "node:child_process";
import { Result } from "../types/result.js";

export class GitExecutor {
  execute(args: string[]): Result<string> {
    // gitコマンドを実行して出力を返す
  }
}
  1. 新しいGit操作の追加
// src/core/git/libs/stash-list.ts
import { GitExecutor } from "../executor.js";
import { Result } from "../../types/result.js";

export function listStashes(): Result<string[]> {
  const git = new GitExecutor();
  const result = git.execute(["stash", "list"]);
  
  if (!result.ok) {
    return result;
  }
  
  const stashes = result.value
    .split("\n")
    .filter(line => line.trim());
    
  return Result.ok(stashes);
}

ローカルテスト戦略

1. 手動テスト

# テストリポジトリを作成
mkdir test-repo && cd test-repo
git init

# phantomコマンドをテスト
pnpm start create feature-1
pnpm start list
pnpm start exec feature-1 "pwd"
pnpm start shell feature-1
pnpm start delete feature-1

2. 統合テスト

# テストスクリプトを作成
cat > test-integration.sh << 'EOF'
#!/bin/bash
set -e

# セットアップ
TEMP_DIR=$(mktemp -d)
cd $TEMP_DIR
git init

# createをテスト
node /path/to/phantom/dist/phantom.js create test1
[ -d ".git/worktrees/test1" ] || exit 1

# listをテスト
node /path/to/phantom/dist/phantom.js list | grep test1 || exit 1

# クリーンアップ
cd ..
rm -rf $TEMP_DIR
echo "統合テストが成功しました!"
EOF

chmod +x test-integration.sh
./test-integration.sh

3. パフォーマンステスト

// シンプルなパフォーマンステスト
console.time("create-worktree");
await createWorktree("perf-test");
console.timeEnd("create-worktree");

// メモリ使用量
const before = process.memoryUsage();
await operation();
const after = process.memoryUsage();
console.log("メモリ差分:", after.heapUsed - before.heapUsed);

IDEセットアップ

Visual Studio Code

  1. 起動設定

.vscode/launch.json:

{
  "version": "0.2.0",
  "configurations": [
    {
      "type": "node",
      "request": "launch",
      "name": "Debug CLI",
      "skipFiles": ["<node_internals>/**"],
      "program": "${workspaceFolder}/src/bin/phantom.ts",
      "args": ["create", "test"],
      "outFiles": ["${workspaceFolder}/dist/**/*.js"],
      "sourceMaps": true,
      "runtimeArgs": ["--loader", "tsx"]
    },
    {
      "type": "node",
      "request": "launch",
      "name": "Debug Current Test",
      "skipFiles": ["<node_internals>/**"],
      "program": "${file}",
      "args": ["--test"],
      "console": "integratedTerminal"
    }
  ]
}
  1. タスク設定

.vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Run Tests",
      "type": "npm",
      "script": "test",
      "problemMatcher": [],
      "group": {
        "kind": "test",
        "isDefault": true
      }
    },
    {
      "label": "Build",
      "type": "npm",
      "script": "build",
      "group": {
        "kind": "build",
        "isDefault": true
      }
    }
  ]
}

デバッグのヒント

  1. ブレークポイントを追加

    • 行番号の横のガッターをクリック
    • コード内でdebugger;ステートメントを使用
  2. 変数を検査

    • デバッグ中に変数にホバー
    • デバッグコンソールで評価を使用
  3. コードをステップ実行

    • F10: ステップオーバー
    • F11: ステップイン
    • Shift+F11: ステップアウト

環境変数

開発に便利:

# デバッグ出力を有効化
DEBUG=phantom:* pnpm start create test

# カスタムphantomディレクトリを使用
PHANTOM_BASE_DIR=/custom/path pnpm start create test

# Node.jsフラグ
NODE_OPTIONS="--trace-warnings" pnpm start

コード品質

コミット前に

必ず実行:

pnpm ready

これは以下を実行します:

  1. コードフォーマット(pnpm fix
  2. 型チェック(pnpm typecheck
  3. ユニットテスト(pnpm test

手動チェック

# 特定のファイルをチェック
npx biome check src/cli/handlers/create.ts

# 特定のファイルを修正
npx biome check --apply src/cli/handlers/create.ts

# 特定のファイルの型チェック
npx tsc --noEmit src/core/worktree/create.ts

トラブルシューティング

よくある問題

  1. モジュールが見つからないエラー
# プロジェクトがビルドされていることを確認
pnpm build

# インポートパスを確認(.js拡張子を含める必要があります)
import { something } from "./module.js";  #
import { something } from "./module";     #
  1. 型エラー
# 詳細について型チェックを実行
pnpm typecheck

# TypeScriptバージョンを確認
npx tsc --version
  1. テストの失敗
# デバッグのために単一のテストを実行
node --test src/core/worktree/create.test.ts

# より多くの出力で実行
node --test --test-reporter=spec

デバッグ出力

デバッグロギングを追加:

// 一時的なデバッグロギング
console.log("Debug:", { name, branch, path });

// 条件付きデバッグ
if (process.env.DEBUG) {
  console.log("Git args:", args);
}

// オブジェクトをきれいに出力
console.log(JSON.stringify(result, null, 2));

ベストプラクティス

1. 型安全性を使用

// 良い: 強い型付け
function createWorktree(
  name: string,
  branch?: string
): Promise<Result<WorktreeInfo>>

// 悪い: Any型
function createWorktree(name: any, options: any): any

2. パターンに従う

// エラーにはResultパターンに従う
return Result.ok(value);
return Result.error(new Error("Failed"));

// 既存のヘルパーを使用
import { validateWorktreeName } from "./validate.js";

3. 最初にテストを書く

# TDDワークフロー
1. 失敗するテストを書く
2. 合格するための最小限のコードを書く
3. リファクタリング
4. 繰り返し

4. シンプルに保つ

  • 過度に設計しない
  • 既存のパターンに従う
  • 不明な場合は質問する

次のステップ

ハッピーコーディング! 🚀

⚠️ **GitHub.com Fallback** ⚠️