Skip to content

v2.9.0

Latest

Choose a tag to compare

@github-actions github-actions released this 16 Aug 15:25
· 2 commits to main since this release
20ed83e

2.9.0 - 2026-08-17

New Feature

Fall back through ssh, gh and https auth when cloning instead of giving up after ssh (#154)

Before This Release

Installing from a private GitHub repo, or updating skills that came from one, failed completely when ssh auth was unavailable or broken.

  • install first tried the https URL with credential helpers disabled, so it only ever succeeded for public repos. On failure it fell back to ssh once, and if ssh failed, the whole operation failed.
  • update cloned the repoUrl stored in the skill metadata. When that was an ssh URL - which it became after a previous fallback - there was no fallback at all, so one ssh failure was a total failure.
  • search (the list / read / install actions) shared the same clone logic as install.

Other auth methods the user may have working, such as gh or https credentials, were never tried.

After This Release

The clone logic now lives in a shared GitClone object used by install, update and search. For a github.com repo, in either URL form, it escalates through the available methods instead of giving up:

Order Method What it does
1 anonymous https with credential helpers disabled (public repos)
2 ssh git@github.com:owner/repo.git (may prompt for a key passphrase)
3 gh gh used as a git credential helper
4 credential-helper https with the configured git credential helper
5 interactive asks first, then hands the terminal to git for its own prompt

The failure is only reported after every method has been tried, and the report says what was attempted:

  ✖ Clone failed
  anonymous: remote: Repository not found.
  ssh: git@github.com: Permission denied (publickey).
  gh: skipped (gh not found on PATH)
  credential-helper: skipped (no git credential helper configured)
SSH, gh, and credential helper access all failed or are unavailable.
? Try https clone with username/password? (git will prompt, use a personal access token as the password) ›
  ‣ Yes          — git will prompt for username/password
    No           — abort

The CLI never reads or stores credentials itself - git does its own prompting, and a personal access token works as the password.

Notes:

  • The interactive last resort only runs when stdin is a TTY and --yes was not passed, so CI and piped runs degrade to the non-interactive steps and then fail with the report instead of hanging.
  • Non-GitHub https URLs also gain the credential-helper and interactive steps. Ssh-form and git:// URLs keep the previous single-attempt behavior.
  • .aiskills.json gains an optional authMethod field recording the method that succeeded. update moves that method to the front of the chain rather than replacing the chain, then rewrites the metadata with whichever method actually won.
  • repoUrl is now always stored in canonical https form for github.com, so it no longer flips between ssh and https across updates. Legacy records holding an ssh URL are repaired on the next successful update.
  • Metadata without authMethod simply runs the full chain, so no migration is needed.

Bug Fixed

Fixed: Skill's subpath should be normalized (#149)

Before This Release

The repo-root state had three representations (None, "" and "."), depending on which command wrote the metadata. aiskills install wrote "subpath": "" while aiskills search wrote "subpath": ".".

As a result, list / read showed

         subpath: .

instead of <root>, and the overwrite / replace prompts showed my-skill (.) instead of my-skill (<root>).

After This Release

The invariant is enforced in SkillSourceMetadata itself, so "", "." and whitespace-only subpaths are all canonicalized to a single representation. The decoder is routed through the same path, so legacy .aiskills.json files already on disk are normalized on read as well, and a repo-root skill is written as "subpath" : null.

         subpath: <root>

Fixed: Show <root> in the install selection list for repo-root skills (#151)

Before This Release

The install selection list interpolated the subpath verbatim, so a repo-root skill rendered as my-skill () while the other display helper already rendered <root> for the same skill.

After This Release

Both display helpers share one helper, so a repo-root skill renders consistently:

? Select skills to install ›
Tab to toggle, Shift+Tab to toggle all, Enter to submit.
 ◉ my-skill                 (<root>)                            12.4KB

Search also builds its Git metadata through Install.buildGitMetadata instead of an inline record, so the Git metadata has a single construction site. This is the duplication that let the "."-subpath bug of #149 exist in only one of the two producers. The written .aiskills.json is unchanged.


Internal Housekeeping

Replace stringly-typed repo URLs with refined4s newtypes and Boolean flags with ADTs (#156)

A type-level refactor with no behavior change.

  • Repo URLs and owner/repo identities used to travel as bare String. Two refined4s types now cover the URL domain across the whole codebase, so there is no String / typed seam at any call site.
    • RepoUrl is an unvalidated newtype covering every accepted clone source - https, ssh, git:// and local .git paths.
    • GitHubOwnerRepo is a refined type whose predicate requires exactly two non-empty segments, so the GitHub URL builders can no longer be handed an arbitrary string.
    • RepoUrl encodes as a plain string, so .aiskills.json is byte-identical to before.
  • Four Boolean flags that carried meaning their type could not express become five ADTs: GhCliStatus, CredentialHelperStatus, Interactivity, TerminalPrompt and InteractiveCloneChoice. The capability gates, the skip notes in the failure report, the env selection and the prompt result handling are all exhaustive matches now, so adding a variant later produces a compiler warning rather than silently falling through.

New dependency:

  • refined4s: 1.20.0 (core, cats and circe modules, added to ai-skills-core)

  • Use .some and Option.when instead of direct Some / None constructors in Install, Search and Update, following the 2020 Hindsight Scala practices for better type inference of Option

What's Changed

  • Reset version: to 2.8.1-SNAPSHOT by @kevin-lee in #148
  • Close #149: Normalize SkillSourceMetadata.subpath so the repo-root subpath has a single representation by @kevin-lee in #150
  • Close #151: Render <root> in the install selection list for repo-root skills and reuse Install.buildGitMetadata in Search by @kevin-lee in #152
  • Refactor by @kevin-lee in #153
  • Close #154: Fall back through ssh, gh, and https auth when cloning instead of giving up after ssh by @kevin-lee in #155
  • Close #156: Replace stringly-typed repo URLs with refined4s newtypes and Boolean flags with ADTs by @kevin-lee in #158
  • ai-skills v2.9.0 by @kevin-lee in #159

Full Changelog: v2.8.0...v2.9.0