This is the opt-in surface for the new go-gh aggressive caching
support. Setting GH_AGGRESSIVE_CACHING_TTL to a Go duration string
(e.g. 30s, 1m, 5m, 1h) enables process-wide TTL caching for cacheable
REST and GraphQL requests on the standard authenticated HTTP client.
Motivation: heavy users running multiple parallel agent harnesses
(e.g. several Codex agents in lockstep) issue duplicate identical
requests within seconds of each other, exhausting the GitHub primary
REST rate limit and tripping secondary limits. A short TTL (~30s)
dedupes the lockstep traffic without changing what gh fundamentally
is. The trade-off (bounded staleness) is acceptable when explicitly
opted into.
Wiring:
- api/http_client.go: NewHTTPClient reads GH_AGGRESSIVE_CACHING_TTL
after honoring caller-supplied EnableCache. The env var only
activates when:
- opts.EnableCache is not already true (caller config wins)
- opts.SkipDefaultHeaders is false (PlainHttpClient bypasses
defaults and must not opt into caching by env var)
Per-request X-GH-CACHE-TTL: 0 still bypasses for individual calls.
- parseAggressiveCachingTTL is silent on failure: empty, '0',
negative, or unparseable values disable the feature. Matches the
convention for other GH_* env vars and avoids stderr noise from
a transport layer. Users diagnose via the X-GH-Cache-Status
response header.
- help_topic.go: documents the env var, format, staleness caveat,
intended use case, observability hook, cleanup path
(gh config clear-cache), and explicit precedence rules.
Tests cover:
- parseAggressiveCachingTTL edge cases (empty, valid, zero,
negative, unparseable, missing unit, plain number).
- Env var with positive duration enables caching end-to-end
(miss -> hit pattern, network call only on first request).
- Env var unset or with invalid value leaves caching disabled.
- Caller-set EnableCache + CacheTTL takes precedence over env var.
- SkipDefaultHeaders (PlainHttpClient path) bypasses aggressive
caching even when env var is set.
- Per-request X-GH-CACHE-TTL: 0 hard-bypasses cache when env var
is set, and does not pollute the cached entry.
Manual smoke verified against live api.github.com:
- REST GET: miss -> hit transitions work, X-GH-Cache-Status
visible via 'gh api -i'.
- GraphQL query: same miss -> hit pattern works.
- Per-request opt-out: header returns no X-GH-Cache-Status,
confirming bypass.
- 'gh auth status', 'gh config clear-cache' continue to work.
Out of scope here:
- ETag / If-None-Match revalidation (planned follow-up that layers
on top of the same transport).
- Rewriting commands like 'gh pr checks --watch' to take advantage
of REST + ETag (separate decision, separate PR).
Depends on go-gh changes:
- 'Fix per-request cache opt-out when global TTL is configured'
- 'Restrict cacheable responses to 2xx'
- 'Skip caching of GraphQL mutations and subscriptions'
- 'Use atomic temp-file + rename for cache writes'
- 'Vary cache key by Accept-Encoding, X-GitHub-Api-Version, ...'
- 'Emit X-GH-Cache-Status response header for cache observability'
Related: cli/cli#13279, cli/cli#13293
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Add skills specific telemetry
* Remove VisibilityFuture, inline goroutine at call sites
The VisibilityFuture/FetchRepoVisibilityAsync/Wait wrapper was an
unidiomatic async abstraction built for a single pattern used in
exactly two call sites. In Go the channel is already the future;
wrapping it in a struct with a Wait(timeout) method adds no value.
Delete the abstraction and inline a local visResult struct,
buffered channel, goroutine, and select at each call site. Behavior
is preserved exactly: err -> "unknown", timeout -> "unknown",
success+public -> include skill_names.
FetchRepoVisibility (synchronous) is kept as-is.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Fix nonsense copilot tests
* Update telemetry tests for public-only dims and search event removal
Production telemetry emission changed:
- preview: skill_owner/skill_repo/skill_name (renamed from skill_names)
are now emitted only when repo_visibility=public.
- install: skill_owner/skill_repo/skill_names are now emitted only
when repo_visibility=public.
- search: the initial skill_search event was removed entirely; the
skill_search_install event no longer carries query/owner dims.
Update tests to match: rename skill_names -> skill_name in preview,
make owner/repo assertions conditional on public visibility in both
preview and install, and reduce the search test to a single event
with explicit Empty assertions for the removed query/owner dims so a
privacy regression cannot pass silently.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Test CategorizeHost and switch telemetry to skill_host_type
Add TestCategorizeHost covering all four classification branches
(github.com, ghes, tenancy, uncategorized) with cases verified
against the real ghauth implementation rather than guessed.
Update install and preview unit tests to assert the new
skill_host_type dimension name, and fix a typo in the preview
acceptance txtar (skill_hos_type -> skill_host_type).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
* Shrink visibility wait and test unknown visibility
The 2s visibilityWaitTimeout was wildly overprovisioned: by the time
telemetry emission reaches the select, the command has already done
several serial GitHub REST calls (and for install, a git sparse-checkout
plus possibly interactive prompts), so the one-call visibility fetch
has almost always completed. Drop the timeout to 200ms — a short safety
net for a stalled REST call, not a wait budget for a healthy one.
Also adds a table-driven case to TestFetchRepoVisibility covering an
unknown/future visibility value from the API, addressing @babakks'
review nitpick.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
---------
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Harden SpawnSendTelemetry against relative executable paths
- Use io.Copy for telemetry subprocess stdin write
- Clean up GH_TELEMETRY/DO_NOT_TRACK help text
- Fall back to built-in defaults (NoOp telemetry) on config load failure
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Removes post-install extension dispatch to keep the stub focused on
installation. Also removes unused args parameter from the run function.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Use cmdutil.DisableAuthCheck instead of raw annotation map
- Convert tests to table-driven format
- Use generic extension name in tests (gh-cool)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Register hidden stub commands for official GitHub extensions (gh-aw,
gh-stack) that offer to install the extension when invoked. This
replaces the error-string-matching approach from the original PR with
proper cobra commands that:
- Avoid false-positive matches on flag values or post-'--' args
- Eliminate conflicting cobra 'Did you mean?' suggestions
- Properly propagate prompt/install errors for correct exit codes
- Are hidden from help output and shell completions
- Use GroupID "extension" so checkValidExtension allows installing over them
- Are registered after extensions and aliases so both take priority
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Introduces a new `agent-task` command under pkg/cmd/agent with strict OAuth (device flow) token validation. Includes comprehensive tests for token source and host validation, and registers the command in the root command set.
This commit changes <github.com> and <ghe.com> references to `github.com` and `ghe.com` so they are visible on the GitHub CLI marketing website.
GitHub Pages will render URLs with a protocol as clickable links, however hostnames are treated as HTML elements and not rendered.
This commit captures the initial command along with functionality and description.
There is an internal discussion about the appropriate place for some of this content.
- added support for `accessible_colors` configuration setting in `gh config` commandset
- updated default configuration file to contain `accessible_colors: disabled`
- add `GH_ACCESSIBLE_COLORS` env var to `gh environment`
- generated mocks via `go generate ./...` including previously missed prompter changes
This commit adds the new environment variable to the `gh environment` help topic.
Additionally, there is a small fix for Go linter for an unused variable raised as a problem.
Fixes#10235
This commit updates the Cobra command logic around extension upgrade checks to be non-blocking.
Previously, we were waiting for 1 second after the extension completed to allow the update checking logic complete, however users want the GitHub CLI to run as far as possible.
- update `gh help environment` to include that upgrade notices only happen when gh or extensions are executed
- update `gh ext --help` to include reference to upgrade notices and points to `gh help environment` for info on disabling
During discussion in cli/cli#9934, we can to the conclusion that the logic around checking for core GitHub CLI updates would diverge from GitHub CLI
extension updates over time. To that end, this commit splits that logic into a separate function with a new environment variable.
After merging in upstream changes regarding local extensions, this commit addresses remaining PR feedback while also bringing the newly merged tests into alignment with other changes.