refactor(skills): backend-agnostic git via wire protocol (fixes Gitea/Forgejo) #13

Merged
cpfarhood merged 2 commits from feat/skills-git-backend-agnostic into dev 2026-05-16 13:51:22 +00:00
cpfarhood commented 2026-05-16 13:16:39 +00:00 (Migrated from github.com)

Summary

  • Replaces the per-host REST shims in the skill import/update/file-read pipeline with a single git-source module that speaks the git smart-HTTP protocol via isomorphic-git + memfs (no execFile, no tempdirs).
  • Fixes the 404 importing public Gitea/Forgejo repos (e.g. https://git.farh.net/<owner>/<repo>): Gitea has no /repos/.../commits/{ref} endpoint, which the previous shim still depended on.
  • Works for any git-capable backend: GitHub, GitLab, Gitea, Forgejo, Bitbucket, generic git-http. Auth via universal token-as-username onAuth covers GitHub PATs, GitLab PATs, Gitea/Forgejo tokens.

What changed

  • New: server/src/services/git-source.ts
    • parseGitSourceUrl — github tree/blob, gitea/forgejo src/branch|commit|tag, gitlab /-/tree|blob, bitbucket /src/{ref}, bare clone URLs.
    • resolveGitRef — one git.listServerRefs call. Handles default branch (HEAD symref), branches, annotated/lightweight tags, SHA passthrough.
    • openRepoSnapshot — shallow singleBranch clone into in-memory fs; listFiles via git.walk, readFile via git.readBlob.
  • company-skills.ts: rewrote readUrlSkillImports, the update-check, and the on-demand file read to use the new module.
  • Stored skill metadata is unchanged (hostname/owner/repo/ref/trackingRef/repoSkillDir); existing rows keep working — clone URL is derived at fetch time. No migration.
  • company-portability.ts still uses the old github-fetch.ts shim (same broken pattern, separate feature). Tracked as a follow-up — not in this PR.

Test plan

🤖 Generated with Claude Code

## Summary - Replaces the per-host REST shims in the skill import/update/file-read pipeline with a single `git-source` module that speaks the git smart-HTTP protocol via `isomorphic-git` + `memfs` (no execFile, no tempdirs). - Fixes the 404 importing public Gitea/Forgejo repos (e.g. `https://git.farh.net/<owner>/<repo>`): Gitea has no `/repos/.../commits/{ref}` endpoint, which the previous shim still depended on. - Works for any git-capable backend: GitHub, GitLab, Gitea, Forgejo, Bitbucket, generic git-http. Auth via universal token-as-username `onAuth` covers GitHub PATs, GitLab PATs, Gitea/Forgejo tokens. ## What changed - New: `server/src/services/git-source.ts` - `parseGitSourceUrl` — github `tree`/`blob`, gitea/forgejo `src/branch|commit|tag`, gitlab `/-/tree|blob`, bitbucket `/src/{ref}`, bare clone URLs. - `resolveGitRef` — one `git.listServerRefs` call. Handles default branch (HEAD symref), branches, annotated/lightweight tags, SHA passthrough. - `openRepoSnapshot` — shallow `singleBranch` clone into in-memory fs; `listFiles` via `git.walk`, `readFile` via `git.readBlob`. - `company-skills.ts`: rewrote `readUrlSkillImports`, the update-check, and the on-demand file read to use the new module. - Stored skill metadata is unchanged (`hostname`/`owner`/`repo`/`ref`/`trackingRef`/`repoSkillDir`); existing rows keep working — clone URL is derived at fetch time. No migration. - `company-portability.ts` still uses the old `github-fetch.ts` shim (same broken pattern, separate feature). Tracked as a follow-up — not in this PR. ## Test plan - [x] \`pnpm --filter @paperclipai/server typecheck\` clean. - [x] Smoke: \`https://git.farh.net/privilegedescalation/org\` (gitea, default branch) — resolves SHA, lists tree, reads files. - [x] Smoke: \`https://github.com/anthropics/claude-code/tree/main\` — github tree URL still works. - [x] Smoke: \`https://git.farh.net/privilegedescalation/org/src/branch/main/skills\` — gitea explicit-branch + subpath. - [ ] Manual: import a private Gitea repo with a PAT through the UI. - [ ] Manual: import a github skill repo (regression). - [ ] Manual: trigger an update check on an existing imported skill. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Sign in to join this conversation.