mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
* Extract client SDK package * Polish SDK client identity defaults * Build client before dependent CI jobs * Restore daemon client server export * Extract protocol and client SDK packages * Fix provider override schema validation * Fix app test daemon client imports * Simplify workspace build targets * Fix CLI test server build bootstrap * Run SDK package tests in CI * Fix rebase package split drift * Restore lockfile registry metadata * Update SDK config test for prompt default * Move terminal stream router test to client package * Fix rebase drift for protocol imports * Fix SDK agent capability fixture * Restore legacy server client exports * Fix server export compatibility test * Advertise custom mode icon client capability * Remove server daemon-client exports * Format rebased mode control import * Fix rebase drift for protocol imports Files added by upstream PRs (#893, #1147, #1154) referenced the pre-split shared/ paths that this branch moves into @getpaseo/protocol. Redirect those imports to the protocol package so typecheck stays green after the rebase.
118 lines
2.7 KiB
TypeScript
118 lines
2.7 KiB
TypeScript
import { parseGitHubRemoteUrl } from "@getpaseo/protocol/git-remote";
|
|
|
|
export type GithubRefKind = "pull" | "issues";
|
|
|
|
export interface GithubRemote {
|
|
owner: string;
|
|
repo: string;
|
|
host: "github.com";
|
|
}
|
|
|
|
export interface GithubRef {
|
|
kind: GithubRefKind;
|
|
number: number;
|
|
owner: string;
|
|
repo: string;
|
|
url: string;
|
|
}
|
|
|
|
interface ParsedGithubUrl {
|
|
kind: GithubRefKind;
|
|
number: number;
|
|
owner: string;
|
|
repo: string;
|
|
}
|
|
|
|
const GITHUB_REF_URL_PATTERN =
|
|
/https?:\/\/github\.com\/([^/\s<>)\]]+)\/([^/\s<>)\]]+)\/(pull|issues)\/(\d+)(?:[/?#][^\s<>)\]]*)?/giu;
|
|
|
|
export function normalizeGithubRemote(remoteUrl: string | null | undefined): GithubRemote | null {
|
|
const trimmed = remoteUrl?.trim();
|
|
if (!trimmed) {
|
|
return null;
|
|
}
|
|
|
|
const identity = parseGitHubRemoteUrl(trimmed);
|
|
if (!identity) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
owner: identity.owner,
|
|
repo: identity.name,
|
|
host: "github.com",
|
|
};
|
|
}
|
|
|
|
export function parseGithubRef(
|
|
text: string | null | undefined,
|
|
remoteUrl: string | null | undefined,
|
|
): GithubRef | null {
|
|
return extractGithubRefs(text, remoteUrl)[0] ?? null;
|
|
}
|
|
|
|
export function extractGithubRefs(
|
|
text: string | null | undefined,
|
|
remoteUrl: string | null | undefined,
|
|
): GithubRef[] {
|
|
const remote = normalizeGithubRemote(remoteUrl);
|
|
const body = text?.trim();
|
|
if (!remote || !body) {
|
|
return [];
|
|
}
|
|
|
|
const refs: GithubRef[] = [];
|
|
const seen = new Set<string>();
|
|
|
|
for (const match of body.matchAll(GITHUB_REF_URL_PATTERN)) {
|
|
const parsed = parseGithubUrlMatch(match);
|
|
if (!parsed || !matchesRemote(parsed, remote)) {
|
|
continue;
|
|
}
|
|
|
|
const dedupeKey = `${parsed.kind}:${parsed.number}`;
|
|
if (seen.has(dedupeKey)) {
|
|
continue;
|
|
}
|
|
seen.add(dedupeKey);
|
|
|
|
refs.push({
|
|
kind: parsed.kind,
|
|
number: parsed.number,
|
|
owner: remote.owner,
|
|
repo: remote.repo,
|
|
url: `https://github.com/${remote.owner}/${remote.repo}/${parsed.kind}/${parsed.number}`,
|
|
});
|
|
}
|
|
|
|
return refs;
|
|
}
|
|
|
|
function parseGithubUrlMatch(match: RegExpMatchArray): ParsedGithubUrl | null {
|
|
const owner = match[1];
|
|
const repo = match[2];
|
|
const kind = match[3];
|
|
const numberText = match[4];
|
|
if (!owner || !repo || !isGithubRefKind(kind) || !numberText) {
|
|
return null;
|
|
}
|
|
|
|
const number = Number.parseInt(numberText, 10);
|
|
if (!Number.isSafeInteger(number) || number <= 0) {
|
|
return null;
|
|
}
|
|
|
|
return { owner, repo, kind, number };
|
|
}
|
|
|
|
function isGithubRefKind(value: string): value is GithubRefKind {
|
|
return value === "pull" || value === "issues";
|
|
}
|
|
|
|
function matchesRemote(parsed: ParsedGithubUrl, remote: GithubRemote): boolean {
|
|
return (
|
|
parsed.owner.toLowerCase() === remote.owner.toLowerCase() &&
|
|
parsed.repo.toLowerCase() === remote.repo.toLowerCase()
|
|
);
|
|
}
|