From d4b8d910ed213949c2c278aa80cc92800e54931b Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 27 May 2026 11:52:29 +0000
Subject: [PATCH 1/5] Initial plan


From dfa1a014781493989504d41acdd18fde3a790ab5 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 27 May 2026 12:15:23 +0000
Subject: [PATCH 2/5] Support slash refs in add workflow specs

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/cli/add_package_manifest_test.go |  5 +++++
 pkg/cli/add_wildcard_test.go         | 14 ++++++++++++++
 pkg/parser/remote_fetch.go           |  9 ++++++++-
 pkg/parser/remote_fetch_test.go      | 21 +++++++++++++++++++++
 4 files changed, 48 insertions(+), 1 deletion(-)
 create mode 100644 pkg/parser/remote_fetch_test.go

diff --git a/pkg/cli/add_package_manifest_test.go b/pkg/cli/add_package_manifest_test.go
index e4c886d331b..8b5e933a79c 100644
--- a/pkg/cli/add_package_manifest_test.go
+++ b/pkg/cli/add_package_manifest_test.go
@@ -521,6 +521,11 @@ func TestParseRepositoryPackageSpec(t *testing.T) {
 			spec:   "owner/repo/workflows/review.md",
 			wantOK: false,
 		},
+		{
+			name:   "workflow path with branch ref is not package",
+			spec:   "owner/repo/agentic-workflows/pr-review.md@feature/github-agentic-workflows",
+			wantOK: false,
+		},
 		{
 			name:   "url is not package",
 			spec:   "https://github.com/owner/repo",
diff --git a/pkg/cli/add_wildcard_test.go b/pkg/cli/add_wildcard_test.go
index fa3fd445402..c4d2443a103 100644
--- a/pkg/cli/add_wildcard_test.go
+++ b/pkg/cli/add_wildcard_test.go
@@ -23,6 +23,7 @@ func TestParseWorkflowSpecWithWildcard(t *testing.T) {
 		expectError    bool
 		expectedRepo   string
 		expectedVer    string
+		expectedPath   string
 	}{
 		{
 			name:           "wildcard_without_version",
@@ -56,6 +57,15 @@ func TestParseWorkflowSpecWithWildcard(t *testing.T) {
 			expectedRepo:   "githubnext/agentics",
 			expectedVer:    "",
 		},
+		{
+			name:           "direct_workflow_path_with_branch_ref_containing_slash",
+			spec:           "owner/repo/agentic-workflows/pr-review.md@feature/github-agentic-workflows",
+			expectWildcard: false,
+			expectError:    false,
+			expectedRepo:   "owner/repo",
+			expectedVer:    "feature/github-agentic-workflows",
+			expectedPath:   "agentic-workflows/pr-review.md",
+		},
 		{
 			name:           "invalid_spec_too_few_parts",
 			spec:           "owner/*",
@@ -100,6 +110,10 @@ func TestParseWorkflowSpecWithWildcard(t *testing.T) {
 			if result.Version != tt.expectedVer {
 				t.Errorf("parseWorkflowSpec() Version = %v, expected %v", result.Version, tt.expectedVer)
 			}
+
+			if tt.expectedPath != "" && result.WorkflowPath != tt.expectedPath {
+				t.Errorf("parseWorkflowSpec() WorkflowPath = %v, expected %v", result.WorkflowPath, tt.expectedPath)
+			}
 		})
 	}
 }
diff --git a/pkg/parser/remote_fetch.go b/pkg/parser/remote_fetch.go
index f7c30c1c9c5..ff332f0112e 100644
--- a/pkg/parser/remote_fetch.go
+++ b/pkg/parser/remote_fetch.go
@@ -9,6 +9,7 @@ import (
 	"fmt"
 	"io"
 	"net/http"
+	"net/url"
 	"os"
 	"os/exec"
 	pathpkg "path"
@@ -432,13 +433,14 @@ func resolveRefToSHA(owner, repo, ref, host string) (string, error) {
 	// Use gh CLI to get the commit SHA for the ref
 	// This works for branches, tags, and short SHAs
 	// Using go-gh to properly handle enterprise GitHub instances via GH_HOST
-	apiPath := fmt.Sprintf("/repos/%s/%s/commits/%s", owner, repo, ref)
+	apiPath := buildCommitLookupAPIPath(owner, repo, ref)
 	var args []string
 	if host != "" {
 		args = []string{"api", "--hostname", host, apiPath, "--jq", ".sha"}
 	} else {
 		args = []string{"api", apiPath, "--jq", ".sha"}
 	}
+
 	stdout, stderr, err := gh.Exec(args...)
 
 	if err != nil {
@@ -453,6 +455,7 @@ func resolveRefToSHA(owner, repo, ref, host string) (string, error) {
 			}
 			return sha, nil
 		}
+
 		return "", fmt.Errorf("failed to resolve ref %s to SHA for %s/%s: %s: %w", ref, owner, repo, strings.TrimSpace(outputStr), err)
 	}
 
@@ -469,6 +472,10 @@ func resolveRefToSHA(owner, repo, ref, host string) (string, error) {
 	return sha, nil
 }
 
+func buildCommitLookupAPIPath(owner, repo, ref string) string {
+	return fmt.Sprintf("/repos/%s/%s/commits/%s", owner, repo, url.PathEscape(ref))
+}
+
 // downloadFileViaGit downloads a file from a Git repository using git commands
 // This is a fallback for when GitHub API authentication fails
 func downloadFileViaGit(owner, repo, path, ref, host string) ([]byte, error) {
diff --git a/pkg/parser/remote_fetch_test.go b/pkg/parser/remote_fetch_test.go
new file mode 100644
index 00000000000..429fcb9bd2a
--- /dev/null
+++ b/pkg/parser/remote_fetch_test.go
@@ -0,0 +1,21 @@
+package parser
+
+import "testing"
+
+func TestBuildCommitLookupAPIPath(t *testing.T) {
+	t.Run("escapes refs containing slash", func(t *testing.T) {
+		got := buildCommitLookupAPIPath("owner", "repo", "feature/github-agentic-workflows")
+		want := "/repos/owner/repo/commits/feature%2Fgithub-agentic-workflows"
+		if got != want {
+			t.Fatalf("buildCommitLookupAPIPath() = %q, want %q", got, want)
+		}
+	})
+
+	t.Run("keeps plain refs readable", func(t *testing.T) {
+		got := buildCommitLookupAPIPath("owner", "repo", "main")
+		want := "/repos/owner/repo/commits/main"
+		if got != want {
+			t.Fatalf("buildCommitLookupAPIPath() = %q, want %q", got, want)
+		}
+	})
+}

From dd121a09fdb2060d340aa0adf3b50134a38e5ae3 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 27 May 2026 12:17:25 +0000
Subject: [PATCH 3/5] Address review feedback for parser tests

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/parser/remote_fetch.go      | 2 ++
 pkg/parser/remote_fetch_test.go | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/pkg/parser/remote_fetch.go b/pkg/parser/remote_fetch.go
index ff332f0112e..770f5e3ce04 100644
--- a/pkg/parser/remote_fetch.go
+++ b/pkg/parser/remote_fetch.go
@@ -472,6 +472,8 @@ func resolveRefToSHA(owner, repo, ref, host string) (string, error) {
 	return sha, nil
 }
 
+// buildCommitLookupAPIPath returns the GitHub commits API path for a ref,
+// URL-escaping the ref segment so branch names containing slashes are valid.
 func buildCommitLookupAPIPath(owner, repo, ref string) string {
 	return fmt.Sprintf("/repos/%s/%s/commits/%s", owner, repo, url.PathEscape(ref))
 }
diff --git a/pkg/parser/remote_fetch_test.go b/pkg/parser/remote_fetch_test.go
index 429fcb9bd2a..fa3b70fc0de 100644
--- a/pkg/parser/remote_fetch_test.go
+++ b/pkg/parser/remote_fetch_test.go
@@ -1,3 +1,5 @@
+//go:build !integration
+
 package parser
 
 import "testing"

From 87712fd1f97fb61c74b3a2bd5f3040c3cb3b6f00 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 27 May 2026 12:35:12 +0000
Subject: [PATCH 4/5] Add manifest route slash-ref coverage

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/cli/add_package_manifest_test.go | 51 ++++++++++++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/pkg/cli/add_package_manifest_test.go b/pkg/cli/add_package_manifest_test.go
index 8b5e933a79c..664c4e041c5 100644
--- a/pkg/cli/add_package_manifest_test.go
+++ b/pkg/cli/add_package_manifest_test.go
@@ -103,6 +103,40 @@ files:
 		assert.Equal(t, []string{"workflows/review.md"}, pkg.InstallationSource)
 	})
 
+	t.Run("uses slash branch ref from manifest route", func(t *testing.T) {
+		previousDefaultBranch := getRepositoryPackageDefaultBranch
+		t.Cleanup(func() {
+			getRepositoryPackageDefaultBranch = previousDefaultBranch
+		})
+		getRepositoryPackageDefaultBranch = func(repoSlug, host string) (string, error) {
+			t.Fatalf("default branch lookup should not be called when version is provided")
+			return "", nil
+		}
+		downloadPackageFileFromGitHubForHost = func(owner, repo, path, ref, host string) ([]byte, error) {
+			assert.Equal(t, "feature/github-agentic-workflow", ref)
+			switch path {
+			case "agentic-workflows/aw.yml":
+				return []byte("name: Repo Assist\nfiles:\n  - workflows/review.md\n"), nil
+			case "agentic-workflows/README.md":
+				return []byte("# Repo Assist\n"), nil
+			default:
+				return nil, createRepositoryPackageNotFoundError(path)
+			}
+		}
+		listPackageWorkflowFilesForHost = func(owner, repo, ref, workflowPath, host string) ([]string, error) {
+			t.Fatalf("unexpected scan of %s", workflowPath)
+			return nil, nil
+		}
+
+		pkg, err := resolveRepositoryPackage(&RepoSpec{
+			RepoSlug:    "owner/repo",
+			PackagePath: "agentic-workflows",
+			Version:     "feature/github-agentic-workflow",
+		}, "github.com")
+		require.NoError(t, err)
+		assert.Equal(t, []string{"agentic-workflows/workflows/review.md"}, pkg.InstallationSource)
+	})
+
 	t.Run("falls back to scanning supported workflow directories", func(t *testing.T) {
 		downloadPackageFileFromGitHubForHost = func(owner, repo, path, ref, host string) ([]byte, error) {
 			switch path {
@@ -502,6 +536,7 @@ func TestParseRepositoryPackageSpec(t *testing.T) {
 		wantErr         string
 		wantRepoSlug    string
 		wantPackagePath string
+		wantVersion     string
 	}{
 		{
 			name:         "repo only package",
@@ -509,6 +544,13 @@ func TestParseRepositoryPackageSpec(t *testing.T) {
 			wantOK:       true,
 			wantRepoSlug: "owner/repo",
 		},
+		{
+			name:         "repo only package with slash branch ref",
+			spec:         "owner/repo@feature/github-agentic-workflow",
+			wantOK:       true,
+			wantRepoSlug: "owner/repo",
+			wantVersion:  "feature/github-agentic-workflow",
+		},
 		{
 			name:            "nested package path",
 			spec:            "owner/repo/packages/repo-assist",
@@ -516,6 +558,14 @@ func TestParseRepositoryPackageSpec(t *testing.T) {
 			wantRepoSlug:    "owner/repo",
 			wantPackagePath: "packages/repo-assist",
 		},
+		{
+			name:            "nested package path with slash branch ref",
+			spec:            "owner/repo/agentic-workflows@feature/github-agentic-workflow",
+			wantOK:          true,
+			wantRepoSlug:    "owner/repo",
+			wantPackagePath: "agentic-workflows",
+			wantVersion:     "feature/github-agentic-workflow",
+		},
 		{
 			name:   "workflow path is not package",
 			spec:   "owner/repo/workflows/review.md",
@@ -556,6 +606,7 @@ func TestParseRepositoryPackageSpec(t *testing.T) {
 			require.NotNil(t, repoSpec)
 			assert.Equal(t, tt.wantRepoSlug, repoSpec.RepoSlug)
 			assert.Equal(t, tt.wantPackagePath, repoSpec.PackagePath)
+			assert.Equal(t, tt.wantVersion, repoSpec.Version)
 		})
 	}
 }

From 824aa3ec7c74d2edef4677e1bbc39e746af651db Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Wed, 27 May 2026 12:47:20 +0000
Subject: [PATCH 5/5] test: expand manifest ref pattern coverage

Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
---
 pkg/cli/add_package_manifest_test.go | 15 +++++++++++++++
 pkg/cli/spec_manifest_source_test.go |  4 ++++
 2 files changed, 19 insertions(+)

diff --git a/pkg/cli/add_package_manifest_test.go b/pkg/cli/add_package_manifest_test.go
index 664c4e041c5..857c53954e2 100644
--- a/pkg/cli/add_package_manifest_test.go
+++ b/pkg/cli/add_package_manifest_test.go
@@ -551,6 +551,13 @@ func TestParseRepositoryPackageSpec(t *testing.T) {
 			wantRepoSlug: "owner/repo",
 			wantVersion:  "feature/github-agentic-workflow",
 		},
+		{
+			name:         "repo only package with sanitized branch characters",
+			spec:         "owner/repo@release/2026.05.27-rc_1",
+			wantOK:       true,
+			wantRepoSlug: "owner/repo",
+			wantVersion:  "release/2026.05.27-rc_1",
+		},
 		{
 			name:            "nested package path",
 			spec:            "owner/repo/packages/repo-assist",
@@ -566,6 +573,14 @@ func TestParseRepositoryPackageSpec(t *testing.T) {
 			wantPackagePath: "agentic-workflows",
 			wantVersion:     "feature/github-agentic-workflow",
 		},
+		{
+			name:            "nested package path with sanitized branch characters",
+			spec:            "owner/repo/agentic-workflows@hotfix/github-aw_fix-1.2.3",
+			wantOK:          true,
+			wantRepoSlug:    "owner/repo",
+			wantPackagePath: "agentic-workflows",
+			wantVersion:     "hotfix/github-aw_fix-1.2.3",
+		},
 		{
 			name:   "workflow path is not package",
 			spec:   "owner/repo/workflows/review.md",
diff --git a/pkg/cli/spec_manifest_source_test.go b/pkg/cli/spec_manifest_source_test.go
index 4c1c88bad71..3043c07e161 100644
--- a/pkg/cli/spec_manifest_source_test.go
+++ b/pkg/cli/spec_manifest_source_test.go
@@ -48,8 +48,12 @@ func TestParseManifestSourceSpec(t *testing.T) {
 		wantVersion  string
 	}{
 		{source: "owner/repo@v1.0.0", wantManifest: true, wantRepo: "owner/repo", wantVersion: "v1.0.0"},
+		{source: "owner/repo@feature/github-agentic-workflow", wantManifest: true, wantRepo: "owner/repo", wantVersion: "feature/github-agentic-workflow"},
+		{source: "owner/repo@release/2026.05.27-rc_1", wantManifest: true, wantRepo: "owner/repo", wantVersion: "release/2026.05.27-rc_1"},
 		{source: "owner/repo/packages/repo-assist@main", wantManifest: true, wantRepo: "owner/repo", wantPackage: "packages/repo-assist", wantVersion: "main"},
+		{source: "owner/repo/agentic-workflows@hotfix/github-aw_fix-1.2.3", wantManifest: true, wantRepo: "owner/repo", wantPackage: "agentic-workflows", wantVersion: "hotfix/github-aw_fix-1.2.3"},
 		{source: "owner/repo/workflows/triage.md@v1.0.0", wantManifest: false},
+		{source: "owner/repo/workflows/triage.md@release/2026.05.27-rc_1", wantManifest: false},
 	}
 
 	for _, tt := range tests {
