diff --git a/skills/xget/SKILL.md b/skills/xget/SKILL.md index 0ad2240..5268c2d 100644 --- a/skills/xget/SKILL.md +++ b/skills/xget/SKILL.md @@ -6,8 +6,6 @@ description: self-hosted Xget instance. Use this skill when a task involves Xget URL rewriting, registry acceleration, proxy base URLs, self-hosting, or choosing the correct Xget prefix for Git, packages, OCI images, or inference APIs. - Prefer the user's own Xget domain; treat the public demo as a last-resort - fallback. license: GPL-3.0-or-later compatibility: Requires network access to refresh the live platform map. Optional Node.js 18+ @@ -17,10 +15,7 @@ allowed-tools: Bash(node:*) Bash(curl:*) Read # Xget -Use this skill for Xget-specific tasks only. Default to the user's self-hosted -Xget domain or an explicit internal instance. Do not default to -`https://xget.xi-xu.me` unless the user explicitly wants the public demo or no -self-hosted option exists. +Use this skill for Xget-specific tasks only. ## Defaults @@ -29,10 +24,8 @@ self-hosted option exists. - `XGET_BASE_URL` from the environment - if neither exists and the task is not just writing docs, ask the user for their self-hosted Xget domain and configure `XGET_BASE_URL` - - `https://xget.example.com` only for docs or templates when a real domain is - not available yet - - `https://xget.xi-xu.me` only as an explicitly labeled fallback after the - user declines or cannot provide a self-hosted domain + - `https://xget.example.com` only as a placeholder in docs or templates when + a real domain is not available yet 2. Keep platform data fresh. Do not hardcode the full prefix list from memory. Run: @@ -97,5 +90,6 @@ node scripts/xget.mjs platforms --format table Report that no current Xget mapping was found. - The default pip snippet should omit `trusted-host`; add it only when the deployment really needs it and keep it aligned with the actual host. -- When generating docs or templates without a real domain, prefer - `https://xget.example.com` over the public demo. +- When generating docs or templates without a real domain, use + `https://xget.example.com` as a clearly labeled placeholder rather than a + default instance. diff --git a/skills/xget/references/REFERENCE.md b/skills/xget/references/REFERENCE.md index f6ccc8b..a69fe68 100644 --- a/skills/xget/references/REFERENCE.md +++ b/skills/xget/references/REFERENCE.md @@ -6,12 +6,10 @@ Use these defaults in order: 1. User-provided Xget base URL 2. `XGET_BASE_URL` from the environment -3. `https://xget.example.com` only for templates and docs -4. `https://xget.xi-xu.me` only as a clearly labeled public-demo fallback +3. `https://xget.example.com` only as a placeholder in templates and docs -The Xget README explicitly labels `xget.xi-xu.me` as a pre-deployed instance -with no reliability guarantee, while the self-hosting docs and DigitalOcean -guide show recommended self-hosted domains such as `xget.example.com`. +This skill should not surface or assume a public demo domain. Prefer +self-hosted guidance and custom-domain examples such as `xget.example.com`. ## Live platform source diff --git a/skills/xget/scripts/xget.mjs b/skills/xget/scripts/xget.mjs index 7f84479..19bcd5b 100644 --- a/skills/xget/scripts/xget.mjs +++ b/skills/xget/scripts/xget.mjs @@ -8,6 +8,7 @@ import vm from 'node:vm'; const DEFAULT_SOURCE_URL = 'https://raw.gitcode.com/xixu-me/xget/raw/main/src/config/platforms.js'; const DEFAULT_BASE_PLACEHOLDER = 'https://xget.example.com'; +const MISSING_BASE_URL_HINT = `Missing --base-url and XGET_BASE_URL. For docs, use ${DEFAULT_BASE_PLACEHOLDER}.`; const CRATES_API_PREFIX = '/api/v1/crates'; @@ -245,6 +246,16 @@ function normalizeBaseUrl(value) { } } +/** + * Resolve an explicit or environment-provided base URL without inventing a fallback instance. + * @param {string | undefined} optionValue + * @param {string | undefined} envValue + * @returns {string | null} + */ +export function resolveBaseUrl(optionValue, envValue) { + return normalizeBaseUrl(optionValue ?? envValue); +} + /** * @param {string} value * @param {string} flagName @@ -590,8 +601,8 @@ async function main() { if (command === 'convert') { const baseUrl = - normalizeBaseUrl(getStringOption(options, 'base-url') ?? process.env.XGET_BASE_URL) ?? - fail(`Missing --base-url and XGET_BASE_URL. For docs, use ${DEFAULT_BASE_PLACEHOLDER}.`, 2); + resolveBaseUrl(getStringOption(options, 'base-url'), process.env.XGET_BASE_URL) ?? + fail(MISSING_BASE_URL_HINT, 2); const rawUrl = getStringOption(options, 'url'); if (!rawUrl) { @@ -630,8 +641,8 @@ async function main() { if (command === 'snippet') { const baseUrl = - normalizeBaseUrl(getStringOption(options, 'base-url') ?? process.env.XGET_BASE_URL) ?? - fail(`Missing --base-url and XGET_BASE_URL. For docs, use ${DEFAULT_BASE_PLACEHOLDER}.`, 2); + resolveBaseUrl(getStringOption(options, 'base-url'), process.env.XGET_BASE_URL) ?? + fail(MISSING_BASE_URL_HINT, 2); const preset = getStringOption(options, 'preset'); if (!preset) { diff --git a/test/unit/xget-skill.test.js b/test/unit/xget-skill.test.js deleted file mode 100644 index 6f9b6ab..0000000 --- a/test/unit/xget-skill.test.js +++ /dev/null @@ -1,77 +0,0 @@ -import { describe, expect, it } from 'vitest'; - -import { PLATFORMS } from '../../src/config/platforms.js'; -import { - buildConvertedUrl, - createPlatformEntries, - createSnippet, - findPlatformForUrl -} from '../../skills/xget/scripts/xget.mjs'; - -const BASE_URL = 'https://xget.example.com'; -const platforms = createPlatformEntries(PLATFORMS); - -/** - * Convert an upstream URL with the xget skill helpers. - * @param {string} url - * @returns {{ platform: { key: string } | null, convertedUrl: string | null }} Converted result. - */ -function convert(url) { - const upstreamUrl = new URL(url); - const platform = findPlatformForUrl(platforms, upstreamUrl); - - return { - platform, - convertedUrl: platform ? buildConvertedUrl(BASE_URL, platform, upstreamUrl) : null - }; -} - -describe('xget skill helpers', () => { - describe('URL conversion', () => { - it('converts Homebrew repository URLs to the homebrew prefix', () => { - const result = convert('https://github.com/Homebrew/homebrew-core/raw/HEAD/Formula/g/git.rb'); - - expect(result.platform?.key).toBe('homebrew'); - expect(result.convertedUrl).toBe( - 'https://xget.example.com/homebrew/homebrew-core/raw/HEAD/Formula/g/git.rb' - ); - }); - - it('converts Homebrew API URLs to the homebrew/api prefix', () => { - const result = convert('https://formulae.brew.sh/api/formula/git.json'); - - expect(result.platform?.key).toBe('homebrew-api'); - expect(result.convertedUrl).toBe('https://xget.example.com/homebrew/api/formula/git.json'); - }); - - it('routes Homebrew bottle URLs to homebrew/bottles instead of cr/ghcr', () => { - const result = convert('https://ghcr.io/v2/homebrew/core/git/manifests/2.39.0'); - - expect(result.platform?.key).toBe('homebrew-bottles'); - expect(result.convertedUrl).toBe( - 'https://xget.example.com/homebrew/bottles/v2/homebrew/core/git/manifests/2.39.0' - ); - }); - - it('normalizes crates.io API URLs to the documented /crates path shape', () => { - const result = convert('https://crates.io/api/v1/crates/serde/1.0.0/download'); - - expect(result.platform?.key).toBe('crates'); - expect(result.convertedUrl).toBe('https://xget.example.com/crates/serde/1.0.0/download'); - }); - }); - - describe('snippets', () => { - it('omits trusted-host from the default pip preset', () => { - const snippet = createSnippet(BASE_URL, 'pip'); - - expect(snippet.commands).toEqual([ - 'pip config set global.index-url https://xget.example.com/pypi/simple/', - 'pip config list' - ]); - expect(snippet.notes).toContain( - 'Only add "pip config set global.trusted-host xget.example.com" when the deployment really needs it.' - ); - }); - }); -});