Commit graph

5613 commits

Author SHA1 Message Date
Sam Morrow
f2d978d960
Disable auth check for local-only skill flags
Add cmdutil.DisableAuthCheckFlag for --from-local on install so that
installing from a local directory does not require authentication.
This follows the same pattern used by attestation verify for its
--bundle flag.

The --dry-run flag on publish is intentionally left with auth enabled
because dry-run validation includes remote repository checks (security
settings, tag protection, topics).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-15 23:49:28 +02:00
Sam Morrow
a6f6ab330f
fix: enforce size cap on first preview file, surface corrupted skills, fail on path traversal
- preview: remove 'fetched > 0' guard so the 512KB size cap applies
  uniformly to all files including the first
- update: return skills with corrupted YAML frontmatter with metadataErr
  set instead of silently dropping them from scan results
- installer: fail installation when a path traversal is detected in
  remote or local skill files instead of silently skipping

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-15 16:53:27 +02:00
Sam Morrow
6c7743eaf1
fix: align relevanceScore comments with implementation and fix typo
- Update comment in relevanceScore() from '10 000 points' to '3 000 points'
  to match the actual implementation value of 3_000
- Update corresponding test comment for consistency
- Fix typo: 'swaped' → 'swapped' in formatStars comment

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-15 16:41:09 +02:00
tommaso-moro
45d0ec0b51
address review comments
Co-authored-by: Sam Morrow <info@sam-morrow.com>
2026-04-15 16:01:26 +02:00
tommaso-moro
1f5a6b8396
clean up interface and fix a few bugs
support specifying a sha in gh skills preview command
2026-04-15 15:50:53 +02:00
tommaso-moro
663df07fcf
cleanup frontmatter fields
remove git sha because we only need git tree sha

remove github-owner from frontmatter, and make github-repo support full url. Only support github.com as host, error out otherwise
2026-04-15 15:47:34 +02:00
tommaso-moro
3b50bbbf16
add .agents/skills as default installation path for hosts that support it: cursor, codex, gemini CLI, github copilot, antigravity.
excluded: claude code
2026-04-15 15:47:34 +02:00
tommaso-moro
b26256a10d
show loading spinner during installation, even for multi-file skills 2026-04-15 15:47:34 +02:00
tommaso-moro
ba61ded4b3
use markdown renderer in preview when previewing multi-file skills 2026-04-15 15:47:34 +02:00
Kynan Ware
8ea84d0dee
Expand test coverage and fix invariants/bugs
Cover the three primary discovery entry points with httpmock-based tests.
DiscoverSkills: happy path, truncated tree, no skills, API error, dedup.
DiscoverSkillByPath: path resolution, namespaces, invalid name, missing
directory, missing SKILL.md. DiscoverLocalSkills: convention matching,
root skill, no skills, nonexistent directory.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test InstallLocal public API instead of private installLocalSkill

Replace tests that called installLocalSkill directly with tests through
InstallLocal. Adds coverage for AgentHost+Scope resolution path,
multiple skills, and missing Dir/AgentHost error. Fixes symlink test
to require.NoError on os.Symlink.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test partial failure in concurrent Install

Add test where one of two skills fails (500 on tree fetch). Asserts
that result.Installed contains the successful skill and err wraps the
failed skill name. Fixes test loop to not clear Dir for partial failure
cases.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Refactor update tests to table-driven pattern

Consolidate 16 individual test functions into 3 standalone + 3 table
tests matching cli/cli conventions. Fix ArgsPassedToOptions to use
iostreams.Test() instead of os.Stdout/os.Stderr. Use GitHub-branded
test data. No coverage lost.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Add update execution test that verifies SKILL.md is rewritten

All prior update tests used DryRun or hit early exits. New test
exercises the full fetch-and-rewrite path: stale treeSHA triggers
re-download, SKILL.md is overwritten with new content and metadata.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Use heredoc.Doc for multiline SKILL.md strings in update tests

Replace escaped newline strings with heredoc.Doc backtick literals
for readability, matching cli/cli conventions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Add interactive update path tests

Cover confirm-and-apply, confirm-cancelled, and no-metadata prompt
paths in TestUpdateRun. These interactive branches were previously
untested since all prior tests used non-TTY or DryRun.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test no-metadata prompt enrichment through full update path

Add test where a skill with no GitHub metadata is prompted for origin,
user provides owner/repo, skill gets enriched and proceeds through
version resolution and file rewrite. Covers lines 222-224 in update.go.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Replace deprecated cs.Gray with cs.Muted

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test namespaced skill update with --dir base resolution

Cover the filepath.Dir double-up path for namespaced skills (name
contains '/') when using --dir. Verifies the install base is resolved
correctly so the update writes to the right directory.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test install failure during update reports error and preserves file

Cover the path where version resolution succeeds but blob fetch fails
during the actual install. Verifies stderr error message, SilentError
return, and that the original SKILL.md is not modified.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Dedupe resolveGitRoot/resolveHomeDir into installer, rename scanAllHosts

Move ResolveGitRoot and ResolveHomeDir to the installer package to
eliminate duplication between install and update commands. Fix
ResolveGitRoot to check RepoDir before calling ToplevelDir.

Rename scanAllHosts to scanAllAgents to match registry naming. Add
test exercising scanAllAgents via updateRun without --dir.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Use heredoc.Doc for multiline YAML strings across all test files

Convert 13 escaped-newline frontmatter strings to heredoc.Doc for
readability. Applies to discovery, frontmatter, install, update,
publish, and preview test files. Preserves edge-case test strings
and fmt.Sprintf interpolations as-is.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Use git.Client.Copy() instead of struct copy to avoid mutex copy

Fixes go vet 'copies lock value' warnings in publish command where
*git.Client was copied by value to set a different RepoDir. Rename
terse variable names (bc/ic/dc) to branchGit/ignoreGit/dirGit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Rewrite publish tests: table-driven through publishRun

Consolidate 35 test functions into 2: TestNewCmdPublish (4 cases for
CLI arg parsing) and TestPublishRun (22 cases exercising all behavior
through the command's run function). No individual helper function
tests — every codepath tested through publishRun scenarios.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Remove .gitkeep from acceptance/testdata/skills

Delete the placeholder .gitkeep file from acceptance/testdata/skills. The directory no longer needs a placeholder file to be tracked in the repository.

Rename testPublishGitClient to newTestGitClient

Rename the test helper function testPublishGitClient to newTestGitClient in pkg/cmd/skills/publish/publish_test.go and update all call sites accordingly. This is a purely refactor/name-change with no behavioral changes to tests.

Fix Windows CI: set USERPROFILE alongside HOME in tests

os.UserHomeDir() uses USERPROFILE on Windows, not HOME. All tests
that redirect HOME for lockfile isolation now also set USERPROFILE
to the same temp directory.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>

Use range-over-int in acquireLock retry loop

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test lock acquisition edge cases through RecordInstall

Make lockRetries and lockRetryInterval configurable (package-level vars)
so tests can avoid the 3s retry wait. Add two RecordInstall cases:
- Stale lock (>30s old) is broken and install succeeds
- Fresh lock exhausts retries, proceeds best-effort without lock

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Rename test helpers for lockfile tests

Rename setupHome to setupTestHome and readLockfile to readTestLockfile in internal/skills/lockfile tests, and update all call sites and comments accordingly. This is a refactor-only change to clarify test helper names with no behavior change.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>

Test read() degradation through RecordInstall, delete TestRead

Move corrupt JSON and wrong version cases into TestRecordInstall table.
RecordInstall calls read() internally, so these exercise the same
degradation paths through the public API. Verifies the lockfile is
rewritten with correct version and new data after recovery.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Fix InstalledAt preservation test to actually prove preservation

Move the update-preserves-InstalledAt case out of the table into a
standalone subtest that reads InstalledAt between two RecordInstall
calls and asserts exact equality. The table version only checked
NotEmpty which couldn't detect if InstalledAt was overwritten.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Merge duplicate plugin test into TestMatchSkillConventions table

The standalone TestDuplicatePluginSkills_DifferentAuthors re-implemented
dedup logic that belongs in DiscoverSkills. Replace with a table case
that tests convention matching only. Dedup is already covered by
TestDiscoverSkills.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Fix broken validateName max-length test case

Replace make([]byte, N) (which produces null bytes) with
strings.Repeat to actually test the 64-character boundary. Add
positive test for valid 64-char name.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Replace name-matching hack with createDir field in TestDiscoverLocalSkills

Use a struct field instead of comparing tt.name to control whether
the test directory is created. Prevents silent breakage if someone
renames the test case.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Improve collisions tests: table-driven FormatCollisions, exercise DisplayName

Convert TestFormatCollisions to table test with nil-input case. Update
single collision case to use different conventions (plugins vs skills)
so DisplayName() logic is actually exercised in the assertion.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Add tests for MatchesSkillPath, DiscoverSkillFiles, ListSkillFiles, FetchDescriptionsConcurrent

Also cover previously untested branches: root convention matching,
annotated tag dereference failure, empty tag_name/default_branch
fallbacks, recursive walkTree with subtrees, and skill directory
deduplication.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test full GitHub key stripping in InjectLocalMetadata

Add all 7 github-* keys to the input metadata and assert all are
absent after injection. Previously only tested github-owner and
github-repo removal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test Serialize trailing-newline addition for body without newline

Add case where body doesn't end in newline and assert the output
has one appended. Previously this branch was uncovered.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test InjectGitHubMetadata with no existing frontmatter

Add case where content has no --- delimiters, exercising the
RawYAML == nil branch that creates frontmatter from scratch.
Also fix test data to use GitHub-branded names.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Convert TestInjectLocalMetadata to table-driven with no-metadata case

Add case for content with no frontmatter, exercising the meta == nil
branch. Aligns with table-driven pattern used throughout.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Replace name-matching hack with useAgentHost field in TestInstallLocal

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Add tests for ResolveGitRoot

Cover RepoDir shortcut, nil client fallback, and empty RepoDir
fallback. Skip ResolveHomeDir — it's a thin os.UserHomeDir wrapper
with no logic to test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Test OnProgress callback in both single and multi-skill Install paths

Cover the progress reporting branches in Install for both the
single-skill fast path (len==1) and the concurrent multi-skill path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Cover missing InstallDir error branches and malformed URL in registry

Add user-scope-without-homeDir and invalid-scope cases to TestInstallDir.
Add malformed URL case to TestRepoNameFromRemote. Coverage 80.5% → 87.8%.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Rewrite install tests: table-driven through installRun and runLocalInstall

Consolidate 48 individual test functions into 6: TestNewCmdInstall (10
cases for CLI parsing), TestInstallRun (21 cases for remote install
flow), TestRunLocalInstall (10 cases for local install flow), plus
TestIsLocalPath, TestIsSkillPath, TestFriendlyDir for pure input
classification. Delete zero-value Help test. All behavior tested
through public functions instead of calling internal helpers directly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Fix data race in OnProgress test with atomic counter

The OnProgress callback was appending to a shared slice from concurrent
goroutines. Replace with sync/atomic counter to avoid the race.

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>

Add interactive install tests for skill selection, scope, host, and overwrite

Exercise the interactive TTY paths in installRun: MultiSelectWithSearch
for skill selection, Select for scope prompt, MultiSelect for host
selection, and Confirm for overwrite declined.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Exercise skillSearchFunc fully through interactive mock

Update the interactive skill selection test to use 31 skills (exceeding
maxSearchResults cap), include a skill without a description, and have
the mock call searchFunc with both empty and filtered queries. Verifies
the MoreResults count, label formatting, and truncation branches.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Fill remaining install coverage gaps

Add local path detection cases to TestNewCmdInstall. Add interactive
repo prompt, user scope selection, overwrite without metadata, and
single exact match cases to TestInstallRun. Add bare tilde expansion
to TestRunLocalInstall.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Move HOME/USERPROFILE setenv to test loops, remove per-case duplication

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Add isTTY field to install test tables, centralize TTY setup

Move TTY configuration from individual opts funcs into the test loops.
Each table case declares isTTY: true/false and the loop sets all three
streams accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Remove INSTALL_TARGET env var hack from install test

Metadata injection is already proven by installer package tests.
This test only needs to verify installRun orchestrates correctly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Add ScopeChanged: true to all install tests with explicit Scope

Ensures tests simulate the same state cobra produces when --scope is
explicitly provided, preventing silent codepath divergence if the
default scope behavior changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Fix assert.Error → require.Error in TestNewCmdSearch

Prevents nil panic on err.Error() if the command unexpectedly returns nil.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Improve preview test quality and coverage

- Fix assert.Error/assert.NoError → require.Error/require.NoError to
  prevent nil panics in TestNewCmdPreview and TestPreviewRun
- Add renderAllFiles edge case tests: maxFiles cap (20 files), maxBytes
  cap (512KB), and FetchBlob error fallback message
- Replace custom discardWriter with io.Discard
- Use GitHub-branded names (monalisa) in new tests

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>

Add search test coverage: rate limits, owner scope, blob enrichment

- Add HTTP 429 and 403+Retry-After rate limit test cases
- Add owner-scoped no-results test (exercises noResultsMessage branch)
- Add blob description enrichment test (exercises fetchDescriptions path)
- Replace custom splitOnSpaces with strings.Fields
- Replace custom discardWriter with io.Discard

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>

Remove low-value alias test for preview command

The test only asserts a string literal matches another string literal.
Alias presence is already visible in the command definition.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Replace local pluralize with text.Pluralize

The internal/text package already provides this function via go-gh.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Inline collapseWhitespace — just strings.Fields + Join

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Doc: suggest using go-humanize for star formatting

Co-Authored-By: Copilot <223556219+Copilot@users.noreply.github.com>

Return cmdutil.CancelError on user cancellation in publish and update

Both commands returned nil (success exit) when the user declined
confirmation. The core CLI pattern is to return CancelError so the
process exits with a non-zero status.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Add interactive publish prompt tests and isTTY field

Cover all prompt branches in runPublishRelease:
- Topic confirm + semver tag selection + final confirm (happy path)
- Custom tag input path (select idx=1)
- Final confirm declined (CancelError)
- Immutable releases prompt (enable via PATCH)

Add isTTY field to test table struct for centralized TTY setup,
matching the pattern used in install tests. Add auto-confirm
prompters to existing TTY tests that now need them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Remove duplicate giturl import alias in publish

The git package was imported twice — once as 'git' and again as
'giturl'. Use git.ParseURL directly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Fix data race in search enrichment

fetchDescriptions and fetchRepoStars run concurrently but both wrote
to fields of the same skillResult slice elements, triggering the race
detector. Refactor both functions to return index-keyed maps instead
of mutating the slice directly. enrichSkills merges the maps into the
slice after both goroutines complete.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

refactor: remove Claude plugin branding, align with Open Plugin Spec

Replace all 'Claude plugin' references with generic 'plugin' terminology
to align with the vendor-neutral Open Plugin Spec
(https://github.com/vercel-labs/open-plugin-spec).

Changes:
- Rename .claude-plugin/ to .plugin/ (spec §5.1 vendor-neutral manifest)
- Rename claudePluginJSON/claudeAuthor types to pluginJSON/pluginAuthor
- Rename claudeMarketplaceJSON to marketplaceJSON
- Rename generateClaudePlugin to generatePlugin
- Remove 'Claude Code' from plugin-related comments, help text, and flags
- Update install.go plugins/ convention message

Factual host references (Claude Code as an agent name, .claude/skills
directories) are intentionally preserved — those are product names, not
plugin branding.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Remove --plugins flag from publish command

Remove the --plugins flag and all associated plugin generation code from
the publish flow. This was scope creep — the publish command should focus
on validating and publishing skills, not generating plugin
manifests.

Removed:
- --plugins flag and Plugins option field
- generatePlugin, generateMarketplace, buildPluginDescription functions
- pluginJSON, marketplaceJSON, marketplacePlugin types
- Related tests and help text

The install command's ability to discover and pluck skills from plugin-
structured repositories (plugins/ convention) is preserved.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

don't fall back on default branch if you can't fetch latest release

improve search algo by using square rot instead of log for stars, and reduce weight for exact name match

add support for --unpin flag when updating a skill
2026-04-15 15:46:58 +02:00
tommaso-moro
40b2a784e3
add core logic and improve test coverage 2026-04-15 15:45:49 +02:00
tommaso-moro
758785b8f4
improve test coverage/cleanup 2026-04-15 15:45:29 +02:00
tommaso-moro
5d049cb897
register initial skills commands 2026-04-15 15:44:00 +02:00
bahtya
57b2477752 Fix infinite loop in 'gh release list --limit 0'
Other list subcommands correctly reject --limit 0 but 'release list'
does not validate the limit, causing an infinite loop.

Add validation consistent with other subcommands and a test.

Closes #13078
2026-04-04 18:13:25 +08:00
William Martin
40da05861a
Merge pull request #13048 from thaJeztah/snappier
replace github.com/golang/snappy with klauspost/compress/snappy
2026-03-31 12:25:44 +02:00
Sebastiaan van Stijn
6868d273ec
replace github.com/golang/snappy with klauspost/compress/snappy
The github.com/golang/snappy repository was archived and is no longer
maintained. klauspost/compress provides a drop-in replacement, which
is actively maintained, and the klauspost/compress module is already
an existing (indirect) dependency.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2026-03-26 22:58:08 +01:00
William Martin
268453803e fix(api): propagate InvokingAgent in gh api HTTP client
The gh api command builds its own HTTP client inline without
forwarding InvokingAgent, so the User-Agent header was missing
the Agent/<name> suffix when invoked by AI coding agents.

Thread InvokingAgent through Factory → ApiOptions → HTTPClientOptions,
mirroring the existing AppVersion pattern.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 16:55:16 +01:00
Kynan Ware
4661c05ed0 Fix gofmt alignment for prompter-enabled fields in IOStreams
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:24:56 +01:00
Kynan Ware
87426ee236 Add experimental huh-only prompter gated by GH_EXPERIMENTAL_PROMPTER
Introduce a new Prompter implementation (huhPrompter) that uses the
charmbracelet/huh library in its standard interactive mode, as an
alternative to the survey-based default prompter. The new implementation
is gated behind the GH_EXPERIMENTAL_PROMPTER environment variable,
following the same truthy/falsey pattern as GH_ACCESSIBLE_PROMPTER.

Key differences from the accessible prompter:
- No WithAccessible(true) flag (full interactive TUI)
- Uses EchoModePassword (masked with *) instead of EchoModeNone
- No default value annotations appended to prompt text

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-26 14:24:56 +01:00
Kynan Ware
8f7d20855e
Merge pull request #13025 from cli/kw/refactor/reviewer-assignee-actor-symmetry
Consolidate actor-mode signals into ApiActorsSupported
2026-03-25 11:43:18 -06:00
William Martin
69d89a6590
Merge pull request #12884 from cli/babakks/use-min-discovery-fields-for-issue-create
fix(issue): avoid fetching unnecessary fields for discovery
2026-03-25 15:39:40 +01:00
Kynan Ware
391e6616d5 fix(survey): use useReviewerSearch consistently in prompt path
The reviewer prompt branch checked reviewerSearchFunc != nil directly
instead of useReviewerSearch, making the fetch and prompt decisions
inconsistent. This mirrors how the assignee path already uses
useAssigneeSearch at both the fetch and prompt gates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 23:28:26 -06:00
Kynan Ware
bff468bafe fix(pr create): wire up @copilot assignee replacement and [bot] suffix
Two bugs introduced in #13009 found during acceptance testing:

1. `pr create --assignee @copilot` sent the literal `@copilot` to the
   API because NewIssueState only ran MeReplacer on assignees, not
   CopilotReplacer. Fixed by switching to SpecialAssigneeReplacer (which
   handles both @me and @copilot) like issue create already does.

2. The replaceActorsForAssignable mutation requires the [bot] suffix on
   bot actor logins (e.g. `copilot-swe-agent[bot]`), unlike
   requestReviewsByLogin which has a separate botLogins field. Added the
   suffix in ReplaceActorsForAssignableByLogin for CopilotAssigneeLogin.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 23:26:28 -06:00
Kynan Ware
6a68ebc1c9 refactor(survey): simplify ApiActorsSupported in RepoMetadataInput
The expression was redundantly re-checking whether assignees or
reviewers were chosen. RepoMetadata already gates on
input.Assignees || input.Reviewers before consulting
ApiActorsSupported, so passing state.ApiActorsSupported directly
is sufficient.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 21:37:58 -06:00
Kynan Ware
ae5e857c2e refactor(featuredetection): rename ActorIsAssignable to ApiActorsSupported
Aligns the feature detector field name with the downstream
ApiActorsSupported flag introduced in the previous commit, so the
signal has one consistent name from detection through to consumption.

Also consolidates leftover TODO tags (actorIsAssignableCleanup,
requestReviewsByLoginCleanup) under the single // TODO ApiActorsSupported
tag so there's exactly one thing to grep for.

Pure rename with no logic changes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 21:09:04 -06:00
Kynan Ware
3c00ffdade refactor(pr shared): consolidate ActorAssignees and ActorReviewers into ApiActorsSupported
The CLI had two per-entity flags (ActorAssignees on EditableAssignees and
IssueMetadataState, ActorReviewers on IssueMetadataState) threaded through
different layers of the stack to distinguish github.com from GHES. Both
flags were always set from the same source (issueFeatures.ActorIsAssignable)
and never had different values, but they were carried independently on
different structs. This led to a confusing asymmetry where:

- EditableAssignees had ActorAssignees but EditableReviewers had nothing
- The PR edit flow piggybacked on editable.Assignees.ActorAssignees to
  make reviewer mutation decisions, which was misleading
- RepoMetadataInput only had ActorAssignees with no reviewer equivalent

This commit replaces all per-entity flags with a single ApiActorsSupported
bool hoisted to the shared level on Editable, IssueMetadataState, and
RepoMetadataInput. Both assignees and reviewers now key off the same signal.

Every branch site is marked with // TODO ApiActorsSupported so we can grep
for cleanup sites when GHES eventually supports the actor-based mutations
(replaceActorsForAssignable, requestReviewsByLogin).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 21:04:41 -06:00
Kynan Ware
1df6f84d70
Merge pull request #13009 from cli/fix/pr-create-assignee-metadata-13000
Use login-based assignee mutation on github.com
2026-03-24 20:29:11 -06:00
Kynan Ware
4e6bc78e04 refactor(pr shared): extract SpecialAssigneeReplacer for @me and Copilot expansion
The inline replaceSpecialAssigneeNames closures in AssigneeIds and
AssigneeLogins were duplicated. Extract them into an exported
SpecialAssigneeReplacer type that consolidates MeReplacer and
CopilotReplacer into a single ReplaceSlice call, parameterised by
actorAssignees and copilotUseLogin.

Adopt the new type in the issue create flow as well, replacing the
manual MeReplacer + conditional CopilotReplacer sequence.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 18:59:21 -06:00
William Martin
1ea2952566
Merge pull request #13023 from cli/agent-in-header
Record agentic invocations in User-Agent header
2026-03-24 20:28:32 +01:00
William Martin
c51769c977 Record agentic invocations in User-Agent header
Detect which AI coding agent is invoking gh by checking well-known
environment variables and include the agent name in the User-Agent
header sent to GitHub APIs.

Supported agents: Codex, Gemini CLI, Copilot CLI, OpenCode,
Claude Code, and Amp. Generic AI_AGENT env var is also supported
with validation to prevent header injection.

Fixes github/cli#1111

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 19:58:37 +01:00
Josh Johanning
761229f057
docs: simplify flag text
applying @BagToad's suggestion to simplify the wording to avoid line wrapping

Co-authored-by: Kynan Ware <47394200+BagToad@users.noreply.github.com>
2026-03-24 10:37:20 -05:00
Kynan Ware
84050fbbad docs(pr edit): improve command examples with grouped sections
Add comment headers to group examples by concern (title/body, labels,
reviewers, assignees, projects/milestones), matching the style used by
other commands like pr review and repo create. Also adds examples for
--body-file and re-requesting review via --add-reviewer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-24 09:20:08 -06:00
Josh Johanning
b9439afa78
docs: clarify that --add-reviewer can re-request reviews
The --add-reviewer flag on pr edit already supports re-requesting
reviews from reviewers who have already submitted their review,
but this wasn't documented in the help text.

Ref #12489
Ref #2053
2026-03-24 09:43:12 -05:00
Kynan Ware
11f177a8c3 feat(pr create, issue create): search-based assignee selection in MetadataSurvey
Wire up MultiSelectWithSearch for assignees in MetadataSurvey, replacing
the static MultiSelect that required bulk fetching all assignable actors.
This applies to both gh pr create and gh issue create interactive flows
when selecting assignees via the 'Add metadata' prompt.

Changes:
- Add assigneeSearchFunc parameter to MetadataSurvey
- Skip assignee bulk fetch when search func is available
- New SearchRepoAssignableActors API function for repo-level search
  (create flows have no issue/PR node ID yet)
- New RepoAssigneeSearchFunc in shared editable.go
- Refactor actorsToSearchResult helper shared by both search functions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-23 18:49:28 -06:00
Kynan Ware
33783748f3 review: address code review feedback
- Fix tests: assert logins (not display names) in actorLogins
- Remove dead ReplaceActorsForAssignableByID (no callers)
- Extract shared AssigneeSearchFunc to pkg/cmd/pr/shared/editable.go
- Remove duplicate assigneeSearchFunc from pr/edit and issue/edit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-23 17:36:52 -06:00
Kynan Ware
947f8fb1b7 refactor(issue edit): wire up search-based assignee selection
Add AssigneeSearchFunc to gh issue edit interactive flow, matching
the pattern already used in gh pr edit. This eliminates the bulk
RepositoryAssignableActors fetch for interactive assignee selection,
using dynamic SuggestedAssignableActors search instead.

Also clean up pr edit assigneeSearchFunc signature to remove the
unused editable parameter (no longer needed after removing the
actor accumulation hack).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-23 17:06:38 -06:00
Kynan Ware
e24f55d5a4 refactor(pr edit): remove actor accumulation hack from assignee search
The assigneeSearchFunc previously accumulated actors into
editable.Metadata.AssignableActors so that MembersToIDs could
later resolve logins to node IDs. Now that the edit flow uses
AssigneeLogins + ReplaceActorsForAssignableByLogin on github.com,
this accumulation is no longer needed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-23 15:34:44 -06:00
Kynan Ware
b3cfe7454c refactor(pr edit, issue edit): use login-based assignee mutation for flag flows
When ActorAssignees is true (github.com), the --add-assignee and
--remove-assignee flag flows now pass logins directly to
ReplaceActorsForAssignableByLogin instead of bulk fetching all
assignable actors and resolving logins to node IDs.

Changes:
- New AssigneeLogins() method on Editable that computes the final
  login set (defaults + add - remove) without ID resolution
- UpdateIssue: call AssigneeLogins + ByLogin when ActorAssignees is true
- EditableOptionsFetch: skip assignee bulk fetch for flag flows on
  github.com (only fetch on GHES where ID resolution is needed)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-23 15:33:37 -06:00
Kynan Ware
e6d9019bc9 fix(pr create): use login-based assignee mutation on github.com
When ActorAssignees is true (github.com), pass assignee logins directly
to the ReplaceActorsForAssignable mutation instead of resolving logins
to node IDs. This eliminates the need to bulk fetch all assignable
users/actors and fixes a bug where providing assignees via CLI flag
and then interactively adding metadata would fail with 'not found'
because the cached MetadataResult had no assignee data.

Changes:
- Set state.ActorAssignees = true in pr create (was missing)
- AddMetadataToIssueParams: pass assigneeLogins when ActorAssignees
  is true, skip fetch and ID resolution entirely
- CreatePullRequest/IssueCreate: call ReplaceActorsForAssignableByLogin
  after creation to assign via logins
- Consolidate replaceActorsForAssignable mutation into api/ package
  (ReplaceActorsForAssignableByLogin + ReplaceActorsForAssignableByID)
- Remove duplicate replaceActorAssigneesForEditable from editable_http.go
- Add TODO replaceActorsByLoginCleanup markers on edit paths

Fixes cli/cli#13000

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-23 15:21:20 -06:00
Kynan Ware
78b958f9ae
fix(agent-task): resolve Copilot API URL dynamically (#12956)
* fix(agent-task): resolve Copilot API URL dynamically

Query viewer.copilotEndpoints.api to get the correct Copilot API URL
for the user's host instead of hardcoding api.githubcopilot.com. This
fixes 401 errors for ghe.com tenancy users whose Copilot API lives at
a different endpoint.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-03-18 18:14:02 +00:00
William Martin
d45acae604
Revert "refactor: deduplicate scope error handling between api/client.go and project queries" 2026-03-12 12:45:48 +01:00
yuvrajangadsingh
198487e166 fix: address review feedback on squash merge commit message
- reorder if checks: validate --enable-squash-merge is set before
  checking the value, and error when --enable-squash-merge=false
- use validSquashMsgValues directly in interactive prompt instead of
  duplicating the slice
- use slices.Contains in validateSquashMergeCommitMsg
- interpolate const values in Long description instead of hardcoding
- add default clause in transformSquashMergeOpts to avoid mutating
  title/message on unknown input
- move optionDiscussions to end of const block with TODO comment
- add test for unknown input and --enable-squash-merge=false case
2026-03-10 18:27:21 +05:30
yuvrajangadsingh
3baf83a339 fix: gofmt alignment in test struct literals 2026-03-10 16:55:50 +05:30
yuvrajangadsingh
4ae0c5851b feat(repo): add --squash-merge-commit-message flag to gh repo edit
Add a single --squash-merge-commit-message flag that maps to both
squash_merge_commit_title and squash_merge_commit_message API fields.

Supported values:
- default: COMMIT_OR_PR_TITLE + COMMIT_MESSAGES
- pr-title: PR_TITLE + BLANK
- pr-title-commits: PR_TITLE + COMMIT_MESSAGES
- pr-title-description: PR_TITLE + PR_BODY

The flag requires --enable-squash-merge to be set alongside it. In
interactive mode, the squash merge commit message prompt appears when
squash merging is selected.

Closes #10092
2026-03-10 16:55:50 +05:30
Yuvraj Angad Singh
78891fc6e5
Merge branch 'trunk' into feature/pr-diff-exclude 2026-03-09 19:35:51 +05:30
yuvrajangadsingh
ea83ca0ca9 refactor: change extractFileName param from []byte to string 2026-03-09 19:26:29 +05:30
Babak K. Shandiz
9f5dfa80c8
test(issue transfer): update stub for IssueRepositoryInfo query
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 11:49:44 +00:00
Babak K. Shandiz
aad0239683
fix(issue transfer): use IssueRepoInfo to fetch minimal fields for issues
Only the destination repo ID is needed for issue transfer. Switch from
GitHubRepo to IssueRepoInfo to use minimal fields appropriate for issues.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 11:49:22 +00:00
Babak K. Shandiz
64416e1ea1
test(issue create): update stubs for IssueRepositoryInfo query
Update test mocks to match the renamed GraphQL query used by
IssueRepoInfo, and switch to StubIssueRepoInfoResponse helper.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 11:35:13 +00:00
Babak K. Shandiz
1d95b633e3
fix(issue create): use IssueRepoInfo to avoid requiring Contents:Read permission
Switch issue create from GitHubRepo to IssueRepoInfo so that
gh issue create works with fine-grained PATs that only have
Issues:Write and Metadata:Read permissions.

Fixes cli/cli#12798

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-03-09 11:33:12 +00:00