feat(sources): support well-known HTTP skill sources#77
Conversation
Add support for bare HTTPS URLs (e.g. `https://cli.sentry.dev`) as skill sources. These are resolved via the `.well-known/skills/` convention: dotagents fetches `{url}/.well-known/skills/index.json` to discover available skills, then downloads each skill's files into a TTL-based cache. Bare HTTPS URLs that don't match GitHub/GitLab patterns are treated as well-known source candidates. If the endpoint doesn't exist, the error message suggests using the `git:` prefix. Closes #74 Agent transcript: https://claudescope.sentry.dev/share/zG7Tq2nDrDatJjftMjoLN2b_zvtpADH05RTyp_Zka3c
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
src/skills/resolver.ts
Fixed
|
|
||
| // Bare HTTP(S) URL not matching GitHub/GitLab — candidate for well-known | ||
| if (/^https?:\/\//i.test(source)) { | ||
| return { type: "well-known", url: source.replace(/\/+$/, "") }; |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
There was a problem hiding this comment.
Fixed — replaced /\/+$/ regex with an iterative stripTrailingSlashes() helper that uses a simple while loop. No regex involved.
— Claude Code
src/sources/wellknown.ts
Fixed
| export async function fetchWellKnownIndex( | ||
| baseUrl: string, | ||
| ): Promise<WellKnownIndex | null> { | ||
| const indexUrl = `${baseUrl.replace(/\/+$/, "")}/.well-known/skills/index.json`; |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
There was a problem hiding this comment.
Fixed — same stripTrailingSlashes() helper approach, no regex.
— Claude Code
src/sources/wellknown.ts
Fixed
| return { cacheDir }; | ||
| } | ||
|
|
||
| const baseUrl = opts.url.replace(/\/+$/, ""); |
Check failure
Code scanning / CodeQL
Polynomial regular expression used on uncontrolled data High
There was a problem hiding this comment.
Fixed — same stripTrailingSlashes() helper approach, no regex.
— Claude Code
Replace /\/+$/ regex (flagged by CodeQL as polynomial on uncontrolled data) with a simple while-loop helper in wellknown.ts and resolver.ts, and an inline slice in add.ts.
- Validate skill.name and file names from remote index.json against safe name pattern to prevent path traversal attacks - Restrict well-known sources to HTTPS only (reject http://) to prevent MITM attacks on skill content
- Use URL.host instead of URL.hostname to preserve port numbers in normalization and cache keys - Remove unused WellKnownError class - Move stripTrailingSlashes to shared utils/fs.ts (deduplicate)
parseSource now only classifies https:// URLs as well-known (not http://). The add command explicitly rejects bare http:// URLs with a clear error message, preventing MITM attacks via plain HTTP skill fetching.
extractDomain and extractDomainPath now use URL.host instead of URL.hostname, consistent with the resolver changes. This ensures git_domains entries with ports (e.g. "localhost:3000") match correctly.
- File paths in well-known index can now contain subdirectories (e.g. "prompts/base.md") while still preventing path traversal - Schema rejects bare "https://" without a hostname - Create parent directories for nested file paths during download
Move the http:// rejection check before parseSource and check against the raw URL with GitHub/GitLab regex exclusions, so http://cli.sentry.dev gets the "Insecure source" error instead of a confusing git clone failure.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
| `Specify skill names as arguments, use --skill to specify which ones, or --all for all skills.`, | ||
| ); | ||
| } | ||
| } |
There was a problem hiding this comment.
Well-known and git add branches heavily duplicated
Low Severity
The well-known branch (lines 200–343) is nearly a verbatim copy of the git branch (lines 344–487). The interactive selection flow — clack.select for all-vs-pick, clack.multiselect, multi-name override handling, duplicate-skip logic, and addWildcard — is identical across both branches except for the cache source (cached.cacheDir vs cached.repoDir). A shared helper accepting the cache directory would eliminate ~140 lines of duplication and reduce the risk of fixing a bug in one branch but not the other.


Summary
Adds support for bare HTTPS URLs as skill sources, resolving via the
.well-known/skills/convention (Issue #74).dotagents add https://cli.sentry.devnow works — fetches{url}/.well-known/skills/index.json, downloads skill files into a TTL-based local cachegit:prefixgit_domainswith prefix-matching (e.g.trust add cli.sentry.dev)Changes
src/sources/wellknown.tsfetchWellKnownIndex,ensureWellKnownCached)src/skills/resolver.tsparseSourcereturns"well-known"for bare HTTPS;resolveSkill/resolveWildcardSkillshandle it;normalizeSourcelowercases hostnamesrc/config/schema.tshttp:///https://URLssrc/trust/validator.ts"well-known"shares domain-matching logic with"git"src/lockfile/schema.tslockedWellKnownSkillSchema(source+resolved_url)src/cli/commands/add.tssrc/cli/commands/install.tsspecs/SPEC.md,docs/public/llms.txthttps://<domain>source typeCloses #74
Test plan
pnpm checkpasses (lint + typecheck + 585 tests)wellknown.test.ts: index fetch (valid/invalid/404/network error), caching (fresh/stale/offline)resolver.test.ts:parseSourcewith well-known URLs,normalizeSource,sourcesMatchvalidator.test.ts: well-known sources againstgit_domainsschema.test.ts: bare HTTPS URLs now acceptednpx @sentry/dotagents add https://cli.sentry.dev(requires network + live endpoint)Agent transcript: https://claudescope.sentry.dev/share/IWLZm9eChduh84Sfd0hyukgm_3Y8F0fp82DqNZzNZ6Q