edc437cdd8
Co-authored-by: Codex <codex@noreply.local>
138 lines
4.7 KiB
TypeScript
138 lines
4.7 KiB
TypeScript
// SPEC: PJ2026-010606 GitHub入口 draft-2026-06-25-gh-split
|
|
// Moved mechanically from scripts/src/gh.ts:5552-5680.
|
|
|
|
import path from "node:path";
|
|
import { bodySafetySignals, bodySha, preview, previewLines, repoParts } from "./auth-and-safety";
|
|
import { githubRequest } from "./client";
|
|
import type { BodyUpdateMode, GitHubBranch, GitHubCompare, GitHubErrorPayload, GitHubOptions, GitHubRepository } from "./types";
|
|
|
|
export function repoSummary(repo: GitHubRepository): Record<string, unknown> {
|
|
return {
|
|
id: repo.id ?? null,
|
|
fullName: repo.full_name ?? null,
|
|
private: repo.private ?? null,
|
|
defaultBranch: repo.default_branch ?? null,
|
|
permissions: repo.permissions ?? null,
|
|
};
|
|
}
|
|
|
|
export function branchSummary(branch: GitHubBranch): Record<string, unknown> {
|
|
return {
|
|
name: branch.name ?? null,
|
|
sha: branch.commit?.sha ?? null,
|
|
};
|
|
}
|
|
|
|
export function compareSummary(compare: GitHubCompare): Record<string, unknown> {
|
|
return {
|
|
status: compare.status ?? null,
|
|
aheadBy: compare.ahead_by ?? null,
|
|
behindBy: compare.behind_by ?? null,
|
|
totalCommits: compare.total_commits ?? null,
|
|
htmlUrl: compare.html_url ?? null,
|
|
baseSha: compare.base_commit?.sha ?? null,
|
|
mergeBaseSha: compare.merge_base_commit?.sha ?? null,
|
|
};
|
|
}
|
|
|
|
export function prUrl(repo: string, number: number): string {
|
|
return `https://github.com/${repo}/pull/${number}`;
|
|
}
|
|
|
|
export function encodePathPart(value: string): string {
|
|
return encodeURIComponent(value);
|
|
}
|
|
|
|
export async function repoInfo(token: string, repo: string): Promise<GitHubRepository | GitHubErrorPayload> {
|
|
const { owner, name } = repoParts(repo);
|
|
return githubRequest<GitHubRepository>(token, "GET", `/repos/${owner}/${name}`);
|
|
}
|
|
|
|
export async function branchInfo(token: string, repo: string, branch: string): Promise<GitHubBranch | GitHubErrorPayload> {
|
|
const { owner, name } = repoParts(repo);
|
|
return githubRequest<GitHubBranch>(token, "GET", `/repos/${owner}/${name}/branches/${encodePathPart(branch)}`);
|
|
}
|
|
|
|
export async function compareBranches(token: string, repo: string, base: string, head: string): Promise<GitHubCompare | GitHubErrorPayload> {
|
|
const { owner, name } = repoParts(repo);
|
|
return githubRequest<GitHubCompare>(token, "GET", `/repos/${owner}/${name}/compare/${encodePathPart(base)}...${encodePathPart(head)}`);
|
|
}
|
|
|
|
export function prCreatePlannedOperation(repo: string, options: GitHubOptions, body: string, bodySource: Record<string, unknown>): Record<string, unknown> {
|
|
return {
|
|
repo,
|
|
title: options.title,
|
|
base: options.base,
|
|
head: options.head,
|
|
draft: options.draft,
|
|
bodyChars: body.length,
|
|
bodyPreview: preview(body),
|
|
bodyPreviewLines: body.split(/\r?\n/).slice(0, 12),
|
|
bodySource,
|
|
preservesRawNewlines: body.includes("\n"),
|
|
containsLiteralBackslashN: body.includes("\\n"),
|
|
containsBackticks: body.includes("`"),
|
|
request: {
|
|
method: "POST",
|
|
path: "/repos/{owner}/{repo}/pulls",
|
|
body: {
|
|
title: options.title,
|
|
base: options.base,
|
|
head: options.head,
|
|
draft: options.draft,
|
|
bodyChars: body.length,
|
|
},
|
|
},
|
|
validation: {
|
|
repo: "required",
|
|
base: "required",
|
|
head: "required",
|
|
title: "required",
|
|
body: body.length > 0 ? "optional" : "empty",
|
|
},
|
|
};
|
|
}
|
|
|
|
export function prCommentPlannedOperation(repo: string, issueNumber: number, body: string, bodySource: Record<string, unknown>): Record<string, unknown> {
|
|
return {
|
|
repo,
|
|
issueNumber,
|
|
bodyChars: body.length,
|
|
bodyPreview: preview(body),
|
|
bodyPreviewLines: body.split(/\r?\n/).slice(0, 12),
|
|
bodySource,
|
|
preservesRawNewlines: body.includes("\n"),
|
|
containsLiteralBackslashN: body.includes("\\n"),
|
|
containsBackticks: body.includes("`"),
|
|
request: {
|
|
method: "POST",
|
|
path: `/repos/{owner}/{repo}/issues/${issueNumber}/comments`,
|
|
body: { bodyChars: body.length },
|
|
},
|
|
validation: {
|
|
repo: "required",
|
|
issueNumber: "required",
|
|
body: "required",
|
|
},
|
|
};
|
|
}
|
|
|
|
export function bodyUpdatePlan(command: string, repo: string, number: number, mode: BodyUpdateMode, body: string, bodySource: Record<string, unknown>, existingBody: string | null): Record<string, unknown> {
|
|
const finalBody = mode === "append" ? `${existingBody ?? ""}${body}` : body;
|
|
return {
|
|
command,
|
|
repo,
|
|
number,
|
|
mode,
|
|
bodySource,
|
|
input: bodySafetySignals(body),
|
|
existingBody: existingBody === null ? { fetched: false } : { fetched: true, bodyChars: existingBody.length, bodySha: bodySha(existingBody) },
|
|
finalBody: {
|
|
bodyChars: finalBody.length,
|
|
bodyPreview: preview(finalBody),
|
|
bodyPreviewLines: previewLines(finalBody),
|
|
...bodySafetySignals(finalBody),
|
|
},
|
|
};
|
|
}
|