import { TOKEN_AREAS } from "../token-scope";
import type { AreaAccess, TokenArea, TokenPermissions } from "../token-scope";
/** Agents get read access everywhere they are granted unless they ask for more. */
const DEFAULT_PERMISSIONS: TokenPermissions = { contents: "read", issues: "read", pulls: "read", actions: "read" };
const MAX_REPO_SCOPES = 50;
const REPO_SCOPE = /^repo:([A-Za-z0-9_.-]+)\/([A-Za-z0-9_.-]+)$/;
/** Asks for the issued token to also work for git, LFS and REST; the user must still tick it at consent. */
export const FORGE_SCOPE = "forge:api";
export const SCOPES_SUPPORTED = [
...TOKEN_AREAS.flatMap((area) => [`${area}:read`, `${area}:write`]),
"repo:{owner}/{name}",
FORGE_SCOPE,
];
export type RequestedScope = {
permissions: TokenPermissions;
repos: Array<{ owner: string; name: string }>;
forge: boolean;
};
function isArea(value: string): value is TokenArea {
return (TOKEN_AREAS as readonly string[]).includes(value);
}
/**
* Scope grammar: `<area>:read|write` for each fine-grained token area and `repo:owner/name` to pin
* the grant to specific repositories. No repo scopes means "all repositories", which the consent
* screen calls out explicitly.
*/
export function parseScope(raw: string | null): RequestedScope {
const permissions: TokenPermissions = {};
const repos: RequestedScope["repos"] = [];
let sawArea = false;
let forge = false;
for (const item of (raw ?? "").split(/\s+/).filter(Boolean)) {
if (item === FORGE_SCOPE) {
forge = true;