akm-cli
Version:
akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cur
65 lines (64 loc) • 2.26 kB
JavaScript
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
import * as childProcess from "node:child_process";
export const GITHUB_API_BASE = "https://api.github.com";
const GITHUB_TOKEN_DOMAINS = new Set(["api.github.com", "github.com", "uploads.github.com"]);
function readGithubTokenFromEnv() {
if (process.env.GITHUB_TOKEN !== undefined) {
return process.env.GITHUB_TOKEN.trim();
}
if (process.env.GH_TOKEN !== undefined) {
return process.env.GH_TOKEN.trim();
}
return undefined;
}
function readGithubTokenFromGhCli() {
const result = childProcess.spawnSync("gh", ["auth", "token", "--hostname", "github.com"], {
encoding: "utf8",
timeout: 5_000,
stdio: ["ignore", "pipe", "ignore"],
});
if (result.status !== 0)
return undefined;
const token = result.stdout.trim();
return token || undefined;
}
function resolveGithubToken() {
const token = readGithubTokenFromEnv();
return token !== undefined ? token || undefined : readGithubTokenFromGhCli();
}
/**
* Build headers for GitHub API requests.
* When a `url` is provided, the Authorization header is only included if the
* URL points to a known GitHub domain, preventing token leakage on redirects
* to third-party hosts.
*/
export function githubHeaders(url) {
const token = resolveGithubToken();
const headers = {
Accept: "application/vnd.github+json",
"User-Agent": "akm-registry",
};
if (token) {
let includeToken = true;
if (url) {
try {
const hostname = new URL(url).hostname;
includeToken = GITHUB_TOKEN_DOMAINS.has(hostname);
}
catch {
includeToken = false;
}
}
if (includeToken)
headers.Authorization = `Bearer ${token}`;
}
return headers;
}
export function asRecord(value) {
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : {};
}
export function asString(value) {
return typeof value === "string" && value ? value : undefined;
}