JA Development Guides Local Development - aku11i/phantom GitHub Wiki
English | 日本語
このガイドでは、開発中のPhantomをローカルで実行する方法について、セットアップ、ワークフロー、一般的なタスクを含めて説明します。
ローカル開発を始める前に、以下があることを確認してください:
- Node.js v22.0.0以上
- pnpm v10.8.1以上
- Git(worktreeサポート付き)
- コードエディター(VS Code推奨)
詳細なインストール手順については、開発セットアップを参照してください。
# リポジトリをクローン
git clone https://github.com/aku11i/phantom.git
cd phantom
# 依存関係をインストール
pnpm install
# セットアップを確認
pnpm test
ソース: package.json#L12
# ソースから直接CLIを実行
pnpm start
# 引数付きで実行
pnpm start create my-feature
pnpm start list
pnpm start exec my-feature "npm test"
コマンド | 説明 | 使用ケース |
---|---|---|
pnpm start |
ソースからCLIを実行 | CLIコマンドのテスト |
pnpm build |
プロジェクトをビルド | 配布物の作成 |
pnpm test |
ユニットテストを実行 | 変更の検証 |
pnpm lint |
コード品質をチェック | 問題の発見 |
pnpm fix |
問題を自動修正 | コードのクリーンアップ |
pnpm typecheck |
型をチェック | 型エラーの検出 |
pnpm ready |
すべてのチェック | コミット前の検証 |
# 新しいブランチを作成
git checkout -b feature/new-command
# 変更を加える
code src/cli/handlers/new-command.ts
# 変更をテスト
pnpm start new-command
# テストを実行
pnpm test
# すべてをチェック
pnpm ready
# 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
# 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/ # 型定義
- ハンドラーファイルを作成
// 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}`);
}
- コアロジックを追加
// 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" });
}
- コマンドを接続
// src/bin/phantom.ts
import { statusHandler } from "../cli/handlers/status.js";
// コマンドスイッチ内
case "status":
await statusHandler(args.slice(1));
break;
- テストを追加
// 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);
});
});
- 現在の動作を理解
# 既存のコードを読む
code src/cli/handlers/create.ts
code src/core/worktree/create.ts
# 既存のテストを確認
code src/core/worktree/create.test.ts
# 現在の実装を実行
pnpm start create test-phantom
- 変更を加える
// createコマンドに新しいオプションを追加
export async function createHandler(args: string[]): Promise<void> {
const [name, branch, customPath] = args;
// カスタムパスサポートを追加
const result = await createWorktree(name, branch, { customPath });
// ...
}
- テストを更新
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モジュールの理解
// 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コマンドを実行して出力を返す
}
}
- 新しい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);
}
# テストリポジトリを作成
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
# テストスクリプトを作成
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
// シンプルなパフォーマンステスト
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);
- 起動設定
.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"
}
]
}
- タスク設定
.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
}
}
]
}
-
ブレークポイントを追加
- 行番号の横のガッターをクリック
- コード内で
debugger;
ステートメントを使用
-
変数を検査
- デバッグ中に変数にホバー
- デバッグコンソールで評価を使用
-
コードをステップ実行
- 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
これは以下を実行します:
- コードフォーマット(
pnpm fix
) - 型チェック(
pnpm typecheck
) - ユニットテスト(
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
- モジュールが見つからないエラー
# プロジェクトがビルドされていることを確認
pnpm build
# インポートパスを確認(.js拡張子を含める必要があります)
import { something } from "./module.js"; # ✓
import { something } from "./module"; # ✗
- 型エラー
# 詳細について型チェックを実行
pnpm typecheck
# TypeScriptバージョンを確認
npx tsc --version
- テストの失敗
# デバッグのために単一のテストを実行
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));
// 良い: 強い型付け
function createWorktree(
name: string,
branch?: string
): Promise<Result<WorktreeInfo>>
// 悪い: Any型
function createWorktree(name: any, options: any): any
// エラーにはResultパターンに従う
return Result.ok(value);
return Result.error(new Error("Failed"));
// 既存のヘルパーを使用
import { validateWorktreeName } from "./validate.js";
# TDDワークフロー
1. 失敗するテストを書く
2. 合格するための最小限のコードを書く
3. リファクタリング
4. 繰り返し
- 過度に設計しない
- 既存のパターンに従う
- 不明な場合は質問する
ハッピーコーディング! 🚀