MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / parseGithubUrl

Function parseGithubUrl

packages/agent-core/src/plugin/source.ts:33–89  ·  view source on GitHub ↗
(raw: string)

Source from the content-addressed store, hash-verified

31}
32
33function parseGithubUrl(raw: string): ResolvedSource | undefined {
34 let url: URL;
35 try {
36 url = new URL(raw);
37 } catch {
38 return undefined;
39 }
40 if (url.protocol !== 'https:') return undefined;
41 if (url.hostname !== 'github.com' && url.hostname !== 'www.github.com') return undefined;
42
43 const segments = url.pathname.split('/').filter((s) => s.length > 0);
44 const owner = segments[0];
45 const repoRaw = segments[1];
46 if (owner === undefined || repoRaw === undefined) return undefined;
47
48 const repo = repoRaw.endsWith('.git') ? repoRaw.slice(0, -4) : repoRaw;
49 const rest = segments.slice(2);
50
51 if (rest.length === 0) {
52 return { kind: 'github', owner, repo };
53 }
54
55 const head = rest[0];
56 const second = rest[1];
57
58 if (head === 'tree' && rest.length >= 2) {
59 // `url.pathname` preserves percent-encoding (e.g. `release%231`). Decode
60 // each segment so the stored ref value is the human-readable Git ref name.
61 // The resolver re-encodes when building the codeload URL.
62 const refValue = decodeRefSegments(rest.slice(1));
63 // We cannot tell branch from tag at parse time. For SHA-shaped values use
64 // kind: 'sha'; otherwise label as 'branch'. The resolver compensates by
65 // using codeload's short-form URL for 'branch' kinds, so codeload itself
66 // picks branch-or-tag — matching how `/tree/<x>` resolves in the GitHub UI.
67 const kind: GithubRef['kind'] = SHA_RE.test(refValue) ? 'sha' : 'branch';
68 return { kind: 'github', owner, repo, ref: { kind, value: refValue } };
69 }
70
71 if (head === 'releases' && second === 'tag' && rest.length >= 3) {
72 // Recognize the canonical "this is a specific release" URL form. Earlier
73 // versions rejected it and pointed users at /tree/<tag>, but /tree/<tag>
74 // could not be parsed as a tag (only branch), which produced a 404 when
75 // codeload was asked for refs/heads/<tag-name>.
76 const tag = decodeRefSegments(rest.slice(2));
77 return { kind: 'github', owner, repo, ref: { kind: 'tag', value: tag } };
78 }
79
80 if (head === 'commit' && rest.length >= 2) {
81 // Mirror the /releases/tag/ change for symmetry: a commit URL pinpoints a
82 // SHA, so accept it directly instead of bouncing users to /tree/<sha>.
83 const sha = decodeRefSegments(rest.slice(1));
84 return { kind: 'github', owner, repo, ref: { kind: 'sha', value: sha } };
85 }
86
87 // /archive/refs/{heads,tags}/X.zip and any other path — fall through to zip-url.
88 return undefined;
89}
90

Callers 1

resolveInstallSourceFunction · 0.85

Calls 1

decodeRefSegmentsFunction · 0.85

Tested by

no test coverage detected