gitnexus-refactoring について
gitnexus-refactoring は、セマンティックなリネームやモジュール、サービスの変更を行う開発者向けの GitNexus スキルです。正しいリポジトリの特定、影響範囲とプレビューの確認、変更後の検証を重視します。
主な機能
- 01リポジトリとワークツリーの特定
- 02依存元とコード参照の把握
- 03セマンティックリネームのプレビュー
- 04確認済みリネーム計画の適用
- 05変更と影響を受ける処理の検証
活用シーン
- 01対応コード内のシンボルのリネーム
- 02コードのモジュールへの抽出
- 03関数やサービスの分割
- 04再構成前の影響範囲の確認
MCP 対応
このスキルは、MCP クライアントが `list_repos`、`impact`、`context`、`rename`、`detect_changes` などの GitNexus ツールを使う手順を示します。`rename` は既定で変更をプレビューし、許可されていれば確認済み計画を適用します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ abhigyanpatwari/ gitnexus --skill gitnexus-refactoringインストール後、Claude Code で/gitnexus-refactoringを入力して読み込まれたか確認します。
詳細
GitNexus でのリファクタリング
使用する場面
- 「この関数を安全に名前変更する」
- 「これをモジュールに切り出す」
- 「このサービスを分割する」
- 「これを新しいファイルに移動する」
- 名前変更、切り出し、分割、またはコードの再構成を伴うあらゆるタスク
最初にリポジトリを指定する
リファクタリングはディスクに書き込みます。dry_run: false を指定した rename は、解決されたリポジトリ内のファイルを編集するため、ここでのリポジトリの識別は単なる記録ではなく、安全性を確保するためのゲートです。
最初のツール呼び出しの前に list_repos {} を呼び出してください。インデックス化されたリポジトリが1つの場合は、以下の例をそのまま使用してください。複数ある場合は、すべての呼び出しで repo を渡してください。通常、repo を省略するとエラーになりますが、デフォルトが設定された MCP ポリシーのもとでは、そのデフォルトに暗黙的に解決されます。どのリポジトリを指しているのか判断できない場合は、作業を中止して確認してください。同じ指定済みリポジトリでプレビューを確認するまでは、dry_run: false を指定した rename を絶対に実行しないでください。返された file_path の値から、これから書き込まれるチェックアウトが分かるため、リポジトリの識別確認として読み取ってください。
list_repos はページ分割されるため、リポジトリが存在しないと判断する前に、hasMore が false になるまで offset: pagination.nextOffset でページを取得してください。
MCP サーバーの起動元とは異なるリンク済みワークツリーを編集している場合、detect_changes には worktree を指定してください。指定しないと、git diff は誤ったチェックアウトで実行され、変更なしと報告されるため、リファクタリングが検証済みであるかのように見えてしまいます。
ワークフロー
0. list_repos {} → Bind repo (and worktree)
1. impact({target: "X", direction: "upstream"}) → Map all dependents
2. query({search_query: "X"}) → Find execution flows involving X
3. context({name: "X"}) → See all incoming/outgoing refs
4. Plan update order: interfaces → implementations → callers → tests
「Index is stale」と表示された場合 → ターミナルで
node .gitnexus/run.cjs analyzeを実行します。
Hot-tool のstalenessは、応答したインデックス(branch/lastCommit)と、その鮮度(status)を示します。再分析が必要なのはbehindまたはdivergedの場合のみです。currentは識別情報、unknownは測定不能を表します。
チェックリスト
シンボルの名前変更
- [ ] list_repos {} — bind repo; explicit repo when >1 indexed, ask if ambiguous
- [ ] rename({symbol_name: "oldName", new_name: "newName", dry_run: true}) — preview semantic edits (omitting dry_run also previews)
- [ ] Confirm the previewed file paths are in the bound repository/worktree
- [ ] Review exact graph-backed semantic spans, coverage, and limitations
- [ ] If satisfied: rename({..., dry_run: false, plan_token: "<token from preview>"}) — apply exactly the reviewed edits
- [ ] detect_changes() — verify only expected files changed
- [ ] Run tests for affected processes
モジュールの切り出し
- [ ] list_repos {} — bind repo; explicit repo when >1 indexed, ask if ambiguous
- [ ] context({name: target}) — see all incoming/outgoing refs
- [ ] impact({target, direction: "upstream"}) — find all external callers
- [ ] Define new module interface
- [ ] Extract code, update imports
- [ ] detect_changes() — verify affected scope
- [ ] Run tests for affected processes
関数/サービスの分割
- [ ] list_repos {} — bind repo; explicit repo when >1 indexed, ask if ambiguous
- [ ] context({name: target}) — understand all callees
- [ ] Group callees by responsibility
- [ ] impact({target, direction: "upstream"}) — map callers to update
- [ ] Create new functions/services
- [ ] Update callers
- [ ] detect_changes() — verify affected scope
- [ ] Run tests for affected processes
ツール
rename — セマンティックな名前変更です。まずプレビューし、その後に適用します。
rename({symbol_name: "validateUser", new_name: "authenticateUser", repo: "my-app", dry_run: true})
→ 12 edits across 8 files
→ semantic_edits: 12, coverage: {name: "gitnexus-semantic", scope: "indexed-repository", limitations: [...]}
→ changes: [{file_path, edits: [{start, length, line, old_text, new_text, confidence: "semantic"}]}]
dry_run を省略するか true にするとプレビューが行われ、書き込みは一切行われません。dry_run: false を指定するには、成功したプレビューの plan_token が必要です。同じリポジトリ、選択したシンボル、移動先の名前を維持してください。トークンは1回のみ使用でき、15分後またはサーバーの再起動後に期限切れになります。また、保持されるプレビューが16プランまたは64 MiBに達すると、追い出される場合があります。適用を試みるたびにトークンは消費されます。再試行する場合は、新しいプレビューを依頼して確認してください。GITNEXUS_MCP_READ_ONLY=1 を指定して起動した MCP サーバーでも rename は表示されますが、プレビュー専用です。省略または true 以外の dry_run は拒否されるため、書き込みが許可されたサーバーで適用してください。そこで新しいプレビューを依頼して確認してください。トークンは発行したプロセスに属します。
名前変更では、インデックス化されたグラフと GitNexus 独自のセマンティックレイヤーを使用します。言語プロバイダーはスコープとバインディングを通じて現在のソースを解決します。コンパイラーや言語サービスは読み込まれません。サポートされていない構文、曖昧なバインディング、古くなった宣言、出現箇所の網羅性が不完全な場合は、安全側に倒して処理を失敗させます。網羅性が示すのは、選択したプロバイダーが受け付けたインデックス内のファイルであり、サポートされている埋め込みソースも含みます。インデックスにないファイルと外部の利用者は含まれません。登録されているすべてのソース言語プロバイダーが名前変更ルールを提供します。宣言やオーバーライドの一連の関係では、完全なセマンティック情報が必要です。プロバイダーが動的または計算された参照を解決できない場合、または選択された一連の関係から除外できない場合、その参照によって名前変更はブロックされます。ファイルの移動を必要とするクラスの名前変更など、プロバイダー固有の制限は結果に明示されます。正規表現によるフォールバックはありません。従来の graph_edits と text_search_edits はゼロです。コメント、文字列、および同じ綴りの無関係なシンボルは置換されません。
プレビューでは、正確なセマンティック計画、ソースハッシュ、物理ファイルの対象が取得されます。適用では、その計画を検証し、再計画せずに編集を実行します。インデックス済みの対象、ソースのバイト列、パス(新たに追加された未追跡のソースファイルを含む)に変更があると、書き込み前に計画が拒否されます。インデックスされていないファイルはセマンティックカバレッジの対象外です。リファクタリングが必要な場合は、まず解析してください。結果では result_version: 2 が使われます。total_edits は一致した行ではなく、出現箇所の数をカウントします。正確な置換内容は new_text に表示されます。planning_status、application_status、applied を確認してください。適用が完了すると、status: "success"、application_status: "applied"、applied: true になります。プレビューが成功しても、ファイルは書き込まれていません。rename は branch を受け付けません。現在のチェックアウトを調査します。
名前変更がブロックされた場合や不完全に終わった場合は、再度適用する前に復旧してください。失敗した結果には code と error が含まれます。最後の行が適用されない限り、何も書き込まれていません。
| 結果 | 次のステップ |
|---|---|
stale_graph | バインドされているリポジトリを再解析してから、rename で再度プレビューします(dry_run は省略するか、true に設定します)。 |
source_changed | 現在のソースに対して再度プレビューし、内容を確認します。適用中に発生した場合は、partial の行を参照してください。 |
plan_required、invalid_plan、plan_mismatch | 適用には、成功したプレビューのトークンと、同一のリポジトリ、シンボル、新しい名前が必要です。期限切れ、使用済み、または破棄されたプランの場合は、確認済みのプレビューを新たに作成してください。 |
source_set_changed | 未追跡ファイルを含むソースパスが変更されています。再解析して、新しいプレビューを確認してください。 |
plan_too_large | キャプチャされたプランが 64 MiB の保持上限を超えています。再度プレビューする前に、インデックス対象のリポジトリを絞り込んでください。 |
unsupported_* | 自動リネームを中止し、報告された制限を確認してください。必要に応じて、言語を考慮した手動リファクタリングを行ってください。 |
対象が曖昧(候補を含む status: "ambiguous") | 返された候補または context を確認し、選択した symbol_uid でプレビューしてください。 |
ambiguous_reference、incomplete_semantics | プランナーは、参照、インポート、または宣言が網羅されていることを証明できませんでした。自動リネームを中止し、指定された場所を手動で解決するか、別のシンボルを選択してください。 |
name_collision | new_name を使うと、別の宣言またはバインディングと衝突するか、その識別子が変わります。別の名前を選んで再度プレビューしてください。 |
invalid_name | new_name が空である、現在の名前と同じである、または対象言語で無効です。有効で、現在の名前とは異なる識別子を選択してください。 |
invalid_argument | dry_run が送信されましたが、ブール値ではありません。省略するか、true または false を送信してください。 |
no_locations | プランナーは編集箇所を生成しませんでした。適用せず、context で対象を再確認し、symbol_uid を渡してください。 |
overlapping_edits、invalid_edit | 計画された範囲が競合しているか、ソーステキストと一致しません。プランは書き込み前に却下されます。適用せず、手動でリファクタリングするか、この事例を報告してください。 |
duplicate_file、missing_snapshot、outside_repository | プランナーの安全性チェックに失敗しました(2 つのパスが同じ実ファイルを指している、ファイルにソーススナップショットがない、またはパスがリポジトリの外に出ている)。再解析して、もう一度プレビューしてください。繰り返し発生する場合は中止して報告してください。 |
source-unavailable(reason: "content-retention" または "checkout-missing") | インデックスは完全なソース保持なしで構築された(GITNEXUS_CONTENT_RETENTION)か、チェックアウトディレクトリがありません。完全な保持を有効にして再解析するか、チェックアウトに対して実行してください。 |
rename_failed | 書き込み前のプランニング中に予期しないエラーが発生しました(application_status: "not_started")。再解析して、もう一度プレビューしてください。繰り返し発生する場合は中止し、error のテキストを報告してください。 |
application_status: "partial" または "failed"(write_failed、または適用中の source_changed) | 書き込みはトランザクションではありません。適用済みの changes(すでに書き込まれたファイルとその件数)、書き込みまたは検証に失敗した 1 つのファイルを示す failed_files、および未処理の後続ファイルを示す unattempted_files を確認してください。現在のファイルを整合させ、再インデックスして、新しいプレビューを確認してください。適用の呼び出しを決してそのまま再試行しないでください。 |
適用後にプロジェクトの検証スイートを実行してください。
impact — まずすべての依存先をマッピングします。
impact({target: "validateUser", repo: "my-app", direction: "upstream"})
→ d=1: loginHandler, apiMiddleware, testUtils
→ Affected Processes: LoginFlow, TokenRefresh
detect_changes — リファクタリング後に変更を検証します。
detect_changes({scope: "all"})
→ Changed: 8 files, 12 symbols
→ Affected processes: LoginFlow, TokenRefresh
→ Risk: MEDIUM
partial: true(グラフクエリに失敗)または truncated: true(変更されたシンボルの一覧が上限に達した)の場合、結果は実際の変更を完全には反映していません。一覧が短い、または空であっても、変更されたのが想定したファイルだけだという証明にはなりません。リファクタリングが検証済みとみなす前に、再実行してください。
誤ったワークツリーに対するゼロ件の結果にはどちらのフラグも付かず、検証に問題がない場合と見分けられません。そのため、差分を確認したチェックアウトが編集対象と同じであることを確認してください。
cypher — カスタム参照クエリ:
MATCH (caller)-[:CodeRelation {type: 'CALLS'}]->(f:Function {name: "validateUser"})
RETURN caller.name, caller.filePath ORDER BY caller.filePath
リスクルール
| リスク要因 | 軽減策 |
|---|---|
| 呼び出し元が多い(>5) | 自動更新には rename を使用します |
| 領域をまたぐ参照 | 適用後に detect_changes を使用して範囲を確認します |
| 文字列/動的参照 | query を使用して検索します |
| 外部/公開 API | 適切にバージョン管理し、非推奨にします |
| 別のインデックス済みリポジトリに同名のものがある | repo を指定し、適用前にプレビューされたパスを確認します |
例:validateUser を authenticateUser に名前変更する
0. list_repos {}
→ total: 2 (my-app, billing-api) — both define validateUser, so bind explicitly
1. rename({symbol_name: "validateUser", new_name: "authenticateUser", repo: "my-app", dry_run: true})
→ 12 semantic occurrences in the indexed repository's supported provider scope
→ Files: validator.ts, login.ts, middleware.ts...
2. Review semantic spans and provider coverage; inspect dynamic references separately
3. rename({symbol_name: "validateUser", new_name: "authenticateUser", repo: "my-app", dry_run: false, plan_token: "<token from step 1>"})
→ Applied 12 edits across 8 files
4. detect_changes({scope: "all", repo: "my-app"})
→ Affected: LoginFlow, TokenRefresh
→ Risk: MEDIUM — run tests for these flows
Repository: my-app (/abs/path/my-app) Worktree: same Index: current
インデックス済みリポジトリが 1 つだけの場合、ステップ 0 は total: 1 を返し、上記のすべての呼び出しで repo 引数は不要になります。