Org-discovery
Functions
discoverOrgRepos
async function discoverOrgRepos(org: string, token: string): Promise<DiscoveredRepo[]>
Use discoverOrgRepos to fetch all repositories in a GitHub organization so you can feed them into skrypt generate for bulk documentation generation.
Reach for this when you want to automate docs across an entire org — for example, generating a unified API reference for every public or private repo your team owns without manually listing them.
It paginates through the GitHub API automatically and returns up to the internal MAX_REPOS limit, sorted by most recently pushed, so the most active repos surface first.
| Name | Type | Required | Description |
|---|---|---|---|
org | string | Yes | The GitHub organization login (the slug in the URL, e.g. "acme-corp" not "Acme Corp"). |
token | string | Yes | A GitHub personal access token or app token with at least repo scope — generate one at github.com/settings/tokens. |
Returns an array of DiscoveredRepo objects, each containing the repo's name, clone URL, and metadata. Pass the clone URLs directly to your skrypt generate pipeline to process each repo in sequence or in parallel.
Heads up:
- The function caps results at an internal
MAX_REPOSlimit — if your org has hundreds of repos, not all will be returned. Sort order (most recently pushed first) means the most active repos are prioritized within that cap. - Requires a token even for public organizations — unauthenticated requests hit GitHub's rate limit of 60/hour, which pagination will exhaust quickly on any org with more than a handful of repos.
Example:
type DiscoveredRepo = {
name: string;
fullName: string;
cloneUrl: string;
pushedAt: string;
private: boolean;
};
async function discoverOrgRepos(
org: string,
token: string
): Promise<DiscoveredRepo[]> {
const repos: DiscoveredRepo[] = [];
let page = 1;
const perPage = 100;
const maxRepos = 500;
while (repos.length < maxRepos) {
const url = `https://api.github.com/orgs/${org}/repos?sort=pushed&direction=desc&per_page=${perPage}&page=${page}`;
const response = await fetch(url, {
headers: {
Authorization: `Bearer ${token}`,
Accept: "application/vnd.github+json",
},
});
if (!response.ok) {
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
}
const data: any[] = await response.json();
if (data.length === 0) break;
for (const repo of data) {
repos.push({
name: repo.name,
fullName: repo.full_name,
cloneUrl: repo.clone_url,
pushedAt: repo.pushed_at,
private: repo.private,
});
}
if (data.length < perPage) break;
page++;
}
return repos.slice(0, maxRepos);
}
async function main() {
try {
const repos = await discoverOrgRepos("vercel", "ghp_your_token_here");
console.log(`Discovered ${repos.length} repos in org`);
console.log("Most recently active:");
repos.slice(0, 3).forEach((repo) => {
console.log(` ${repo.fullName} — pushed ${repo.pushedAt} (${repo.private ? "private" : "public"})`);
});
// Ready to pipe into skrypt generate:
// for (const repo of repos) {
// await exec(`skrypt generate ${repo.cloneUrl} -o ./docs/${repo.name}`);
// }
} catch (err) {
console.error("Failed to discover repos:", err);
}
}
main();
cloneRepoToTemp
async function cloneRepoToTemp(repo: DiscoveredRepo, token: string): Promise<string>
Use cloneRepoToTemp to securely clone a remote repository into a temporary directory so skrypt can scan its source files for documentation generation.
Reach for this when you need to generate docs from a repository you don't have locally — for example, in a CI pipeline or a GitHub App workflow where you're processing repos on demand. It fits into the autodocs flow just before you pass a source path to skrypt generate.
The clone is shallow (depth 1) to keep it fast, and the underlying git call uses array arguments rather than a shell string, which prevents shell injection attacks from malicious repo names or tokens. The temp directory is uniquely named per repo so concurrent clones don't collide.
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
repo | DiscoveredRepo | Yes | The repository to clone — must include at least name (used to name the temp dir) and url (the remote URL git will clone from) |
token | string | Yes | A GitHub personal access token or OAuth token with repo read access — embedded into the clone URL to authenticate the request |
Returns
Returns a Promise<string> that resolves to the absolute path of the temp directory containing the cloned repo (e.g. /tmp/skrypt-my-repo-x7k2p1). Pass this path directly to skrypt generate as the source argument, then delete the directory when you're done.
Heads up
- The temp directory is not cleaned up automatically — call
rmSync(tempDir, { recursive: true })in afinallyblock to avoid filling disk on long-running processes. - The token is embedded in the git URL, so avoid logging the returned path or the
repo.urlin environments where logs are externally visible.
Example:
import { mkdtempSync, rmSync } from "fs";
import { join } from "path";
import { tmpdir } from "os";
import { spawnSync } from "child_process";
interface DiscoveredRepo {
name: string;
url: string;
defaultBranch?: string;
}
async function cloneRepoToTemp(
repo: DiscoveredRepo,
token: string
): Promise<string> {
const tempDir = mkdtempSync(join(tmpdir(), `skrypt-${repo.name}-`));
const authenticatedUrl = repo.url.replace(
"https://",
`https://x-access-token:${token}@`
);
const result = spawnSync(
"git",
["clone", "--depth", "1", authenticatedUrl, tempDir],
{ encoding: "utf8" }
);
if (result.status !== 0) {
rmSync(tempDir, { recursive: true, force: true });
throw new Error(`git clone failed: ${result.stderr}`);
}
return tempDir;
}
const repo: DiscoveredRepo = {
name: "payments-sdk",
url: "https://github.com/acme-corp/payments-sdk",
defaultBranch: "main",
};
const token = "ghp_A1b2C3d4E5f6G7h8I9j0K1l2M3n4O5p6Q7r8";
let clonedPath: string | null = null;
try {
clonedPath = await cloneRepoToTemp(repo, token);
console.log(`Cloned to: ${clonedPath}`);
// => Cloned to: /tmp/skrypt-payments-sdk-x7k2p1
// Pass to skrypt generate:
// execSync(`skrypt generate ${clonedPath} -o ./content/docs`);
} catch (err) {
console.error("Clone failed:", err);
} finally {
if (clonedPath) {
rmSync(clonedPath, { recursive: true, force: true });
console.log("Temp directory cleaned up.");
}
}