diff --git a/AGENTS.md b/AGENTS.md index f3b75e8..86a603b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -58,6 +58,8 @@ Codex / Claude 向けの agent、skill、設定、プロンプトを管理し、 ## ブランチ運用 +- worktree で作業するブランチには、`worktrees/<番号>/` prefix を付けます(例: `worktrees/1/feat/refine-ui`)。 +- worktree 以外で作業するブランチには、`chore/`、`fix/`、`feat/`、`docs/`、`refactor/` のいずれかの prefix を付けます。 - 作業ブランチをデフォルトブランチの最新状態へ追従させるときは、merge や `git rebase` ではなく `grape rebase` を使用します。 ## 配布時の確認 diff --git a/codex/skills/internal/cmd-start-branch/SKILL.md b/codex/skills/internal/cmd-start-branch/SKILL.md index 99197f2..9c8a50c 100644 --- a/codex/skills/internal/cmd-start-branch/SKILL.md +++ b/codex/skills/internal/cmd-start-branch/SKILL.md @@ -35,9 +35,11 @@ description: Git リポジトリで新しい作業を始める前に、最新の - ローカル差分や競合リスクがある場合は止めて、ブランチ作成前に状況を報告する。 4. タスク内容からブランチ名を作る。 - 「ブランチ種別の選び方」の表から、指示内容に最も合う種別を選ぶ。 - - 形式は `/` にする。 + - `git rev-parse --show-toplevel` で、現在地が `.worktrees/<番号>` の worktree か確認する。 + - worktree では `worktrees/<番号>//`、それ以外では `/` の形式にする。 + - worktree の番号を特定できない場合は推測せず、ユーザーへ確認する。 - 英小文字、数字、ハイフンを使う。 - - 例: `feat/add-start-branch-skill`, `fix/login-timeout`, `refactor/split-auth-service` + - 例: `worktrees/1/feat/add-start-branch-skill`, `fix/login-timeout`, `refactor/split-auth-service` 5. `git checkout -b ` で作業ブランチを作成する。 - 同名ブランチがある場合は、既存ブランチの位置と状態を確認し、上書きせず別名を提案する。 6. `$cmd-dispatch-agent` を使って、別 agent に `$cmd-rmbranch` を依頼する。 @@ -55,7 +57,7 @@ description: Git リポジトリで新しい作業を始める前に、最新の ## ブランチ名の判断 - ユーザーがタスク名や Issue 番号を示している場合は、それを優先する。 -- Issue 番号がある場合は `feat/123-short-task` のように先頭へ入れる。 +- Issue 番号がある場合は `feat/123-short-task` のようにタスク名の先頭へ入れる。worktree では `worktrees/1/feat/123-short-task` のようにする。 - まだ内容が薄い場合は `chore/start-task-branch` のような仮名にし、後で必要なら rename を提案する。 - 既存ブランチと衝突する場合は末尾に短い識別子を足す。 @@ -70,12 +72,8 @@ description: Git リポジトリで新しい作業を始める前に、最新の | `feat` | 新機能、既存機能へのユーザー向け能力追加 | `feat/report-filter`, `feat/42-export-csv` | | `fix` | バグ修正、不具合回避、期待と違う挙動の修正 | `fix/login-timeout`, `fix/price-rounding` | | `refactor` | 挙動を変えない構造整理、責務分割、命名整理 | `refactor/split-auth-service`, `refactor/repository-contract` | -| `test` | テスト追加、テスト修正、fixture や検証手順の整備 | `test/add-order-cases`, `test/stabilize-api-spec` | -| `perf` | 性能改善、メモリ削減、クエリ最適化 | `perf/cache-rate-lookup`, `perf/reduce-render-cost` | -| `style` | フォーマット、lint、見た目だけのコード整形。UI 見た目変更は `feat` または `fix` を優先する | `style/format-go-files`, `style/lint-imports` | -| `ci` | CI、ワークフロー、ビルドパイプライン、リリース自動化 | `ci/add-test-workflow`, `ci/cache-go-build` | | `docs` | README、設計メモ、Runbook など文書だけの変更 | `docs/update-runbook`, `docs/add-skill-guide` | -| `chore` | 依存更新、設定整理、生成物更新、運用上の雑務。上記に当てはまるならそちらを優先する | `chore/update-deps`, `chore/start-task-branch` | +| `chore` | テスト、性能、整形、CI、依存更新、設定整理、生成物更新など、他の種別に当てはまらない保守作業 | `chore/add-order-tests`, `chore/add-test-workflow` | ## 報告に含めること diff --git a/codex/skills/internal/cmd-start-branch/evals/evals.json b/codex/skills/internal/cmd-start-branch/evals/evals.json index 842dbab..b0d8bda 100644 --- a/codex/skills/internal/cmd-start-branch/evals/evals.json +++ b/codex/skills/internal/cmd-start-branch/evals/evals.json @@ -25,7 +25,14 @@ { "id": 4, "prompt": "GitHub Actions の Go テスト CI を追加する作業ブランチを作って", - "expected_output": "CI ワークフロー変更として ci を選び、Go テスト CI 用のブランチを最新デフォルトブランチから作成して、不要ブランチ整理を非同期 agent に依頼する。", + "expected_output": "他の種別に当てはまらない CI の保守作業として chore を選び、Go テスト CI 用のブランチを最新デフォルトブランチから作成して、不要ブランチ整理を非同期 agent に依頼する。", + "files": [], + "should_fire": true + }, + { + "id": 5, + "prompt": ".worktrees/3 で Issue 42 のレポート画面改善を始めるのでブランチを作って", + "expected_output": "worktree のスロット番号 3 とユーザー向け能力追加の feat を使い、worktrees/3/feat/42-report-improvement のような形式でブランチを作成して、不要ブランチ整理を非同期 agent に依頼する。", "files": [], "should_fire": true } diff --git a/docs/skill-library.md b/docs/skill-library.md index e7c131d..89d3e4a 100644 --- a/docs/skill-library.md +++ b/docs/skill-library.md @@ -24,7 +24,7 @@ skill 間の明示的な併用・優先関係は [docs/skill-dependency-map.md]( | `cmd-create-pr` | GitHub Pull Request を安全な手順で作成または更新する。 | PR 作成、PR 提出、pull request 作成を依頼されたとき。差分確認、検証、commit、role-reviewer による PR 前レビュー、High 指摘の自動対応、grape push、PR description 作成、gh pr create / edit の順序を整理する。 | | `cmd-dispatch-agent` | 指定された agent を起動し、結果を待たずにタスクを投げる。 | ユーザーが agent 起動、worker への委譲、投げっぱなし実行を明示したとき。明示がなくても、単純で不明瞭な点がない自己完結タスクを任せたいとき。 | | `cmd-rmbranch` | `main` と `develop` を残し、不要なローカルブランチを安全に削除する。 | ローカルブランチ整理を依頼されたとき。未マージブランチは確認してから扱う。 | -| `cmd-start-branch` | 最新のデフォルトブランチから作業ブランチを作り、不要ブランチ整理を非同期に依頼する。 | 新しい作業を始める前に「ブランチ切って」「作業開始用ブランチを作って」などを依頼されたとき。ブランチ名を報告してタスク詳細を待つ。 | +| `cmd-start-branch` | 最新のデフォルトブランチから許可された prefix の作業ブランチを作り、不要ブランチ整理を非同期に依頼する。 | 新しい作業を始める前に「ブランチ切って」「作業開始用ブランチを作って」などを依頼されたとき。ブランチ名を報告してタスク詳細を待つ。 | | `beautify-commit` | ベースブランチまたは基準 commit との差分を、意味のある変更単位の commit へ安全に整理する。 | commit 分割、履歴整理、大きすぎる差分の再 commit、ベースブランチや commit hash を基準にした差分整理を依頼されたとき。interactive rebase が必要な整理は grape の対応まで実行しない。 | | `ci-fix` | GitHub Actions / CI の失敗を調査し、原因切り分けから修正、再検証まで進める。 | CI、GitHub Actions、checks、workflow、test / lint / build failure の修正を依頼されたとき。 | | `code-refactor` | 挙動を変えずにコードを簡略化、リファクタリングする。 | レビュー指摘、quality report、diff、指定ファイルをもとに可読性、保守性、テスト容易性を改善するとき。 | diff --git a/external-skills.json b/external-skills.json index 149e03c..6c409c7 100644 --- a/external-skills.json +++ b/external-skills.json @@ -8,7 +8,7 @@ }, { "name": "grilling", - "url": "https://github.com/mattpocock/skills/blob/main/skills/productivity/grilling/SKILL.md", + "url": "https://github.com/mattpocock/skills/blob/697d4ce9742da558fd1ba6697c8e9775e2e302dd/skills/productivity/grilling/SKILL.md", "type": "git", "treeHash": "10b0db61f9b3869243db8a1a0ee84f862139b94e", "destination": [ diff --git a/scripts/deploy/README.md b/scripts/deploy/README.md index 74bab0a..ad01e48 100644 --- a/scripts/deploy/README.md +++ b/scripts/deploy/README.md @@ -149,7 +149,7 @@ make build-deploy ] ``` -`type` は現在 `git` のみ対応します。`url` は `https://github.com///tree//` 形式、または `https://github.com///blob///SKILL.md` 形式を受け付けます。`treeHash` は必須で、`url` が指す skill ディレクトリの Git tree hash と照合する 40 文字の hex hash を指定します。dry-run でも取得、tree hash 照合、`SKILL.md` の存在確認を行うため、URL が不正、取得できない、tree hash が一致しない、または取得先に `SKILL.md` がない場合はエラーになります。 +`type` は現在 `git` のみ対応します。`url` は `https://github.com///tree//` 形式、または `https://github.com///blob///SKILL.md` 形式を受け付けます。`` には branch、tag、40 文字の commit SHA を指定できます。`treeHash` は必須で、`url` が指す skill ディレクトリの Git tree hash と照合する 40 文字の hex hash を指定します。dry-run でも取得、tree hash 照合、`SKILL.md` の存在確認を行うため、URL が不正、取得できない、tree hash が一致しない、または取得先に `SKILL.md` がない場合はエラーになります。 対象ディレクトリの tree hash は次のように確認できます。 diff --git a/scripts/deploy/internal/external/external.go b/scripts/deploy/internal/external/external.go index ef8f23f..cb1cb64 100644 --- a/scripts/deploy/internal/external/external.go +++ b/scripts/deploy/internal/external/external.go @@ -254,7 +254,7 @@ func (f GitFetcher) Fetch(skill Skill, workDir string) (string, error) { repoDir := filepath.Join(workDir, safePathName(skill.Name)) cloneURL := fmt.Sprintf("https://github.com/%s/%s.git", skillURL.owner, skillURL.repo) - if _, err := f.run("clone", "--depth", "1", "--filter=blob:none", "--sparse", "--branch", skillURL.ref, cloneURL, repoDir); err != nil { + if err := f.clone(skillURL.ref, cloneURL, repoDir); err != nil { return "", err } if err := f.verifyTreeHash(skill, skillURL, repoDir); err != nil { @@ -266,6 +266,22 @@ func (f GitFetcher) Fetch(skill Skill, workDir string) (string, error) { return filepath.Join(repoDir, filepath.FromSlash(skillURL.path)), nil } +func (f GitFetcher) clone(ref, cloneURL, repoDir string) error { + if !gitObjectHashPattern.MatchString(ref) { + _, err := f.run("clone", "--depth", "1", "--filter=blob:none", "--sparse", "--branch", ref, cloneURL, repoDir) + return err + } + + if _, err := f.run("clone", "--depth", "1", "--filter=blob:none", "--sparse", "--no-checkout", cloneURL, repoDir); err != nil { + return err + } + if _, err := f.run("-C", repoDir, "fetch", "--depth", "1", "origin", ref); err != nil { + return err + } + _, err := f.run("-C", repoDir, "checkout", "--detach", "FETCH_HEAD") + return err +} + func (f GitFetcher) verifyTreeHash(skill Skill, skillURL githubSkillURL, repoDir string) error { actual, err := f.run("-C", repoDir, "rev-parse", "HEAD:"+skillURL.path) if err != nil { diff --git a/scripts/deploy/internal/external/external_test.go b/scripts/deploy/internal/external/external_test.go index 0333841..8c08922 100644 --- a/scripts/deploy/internal/external/external_test.go +++ b/scripts/deploy/internal/external/external_test.go @@ -129,6 +129,35 @@ func TestGitFetcherFetchUsesParentDirectoryForSkillBlobURL(t *testing.T) { } } +func TestGitFetcherFetchChecksOutCommitRef(t *testing.T) { + var calls []string + skill := testSkill("grilling") + skill.URL = "https://github.com/owner/repo/blob/697d4ce9742da558fd1ba6697c8e9775e2e302dd/skills/productivity/grilling/SKILL.md" + fetcher := GitFetcher{runGit: func(args ...string) (string, error) { + calls = append(calls, strings.Join(args, " ")) + if isRevParseTree(args, "skills/productivity/grilling") { + return testTreeHash + "\n", nil + } + return "", nil + }} + + if _, err := fetcher.Fetch(skill, t.TempDir()); err != nil { + t.Fatal(err) + } + if len(calls) != 5 { + t.Fatalf("expected clone, fetch, checkout, rev-parse, sparse-checkout calls, got %v", calls) + } + if !strings.Contains(calls[0], "--no-checkout") || strings.Contains(calls[0], "--branch") { + t.Fatalf("commit ref clone should not use --branch: %v", calls) + } + if !strings.HasSuffix(calls[1], "fetch --depth 1 origin 697d4ce9742da558fd1ba6697c8e9775e2e302dd") { + t.Fatalf("unexpected commit fetch call: %v", calls) + } + if !strings.HasSuffix(calls[2], "checkout --detach FETCH_HEAD") { + t.Fatalf("unexpected commit checkout call: %v", calls) + } +} + func TestGitFetcherFetchRejectsTreeHashMismatch(t *testing.T) { actual := "abcdef0123456789abcdef0123456789abcdef01" fetcher := GitFetcher{runGit: func(args ...string) (string, error) {