refactor(scripts): migrate JavaScript tools to TypeScript (#121005)

* refactor(scripts): migrate JavaScript tools to TypeScript

* fix(ci): keep changed-scope preflight zero-install

* fix(ci): preserve zero-install script owners

* fix(ci): complete script migration follow-through

* fix(release): keep stable closeout zero-install

* fix(scripts): preserve standalone execution boundaries

* fix(scripts): repair standalone loader boundaries

* fix(scripts): normalize gateway observation ids

* fix(scripts): keep Docker packager standalone

* test(scripts): preserve rebase cleanup helpers

* test(sessions): use tracked temp directory
This commit is contained in:
Peter Steinberger
2026-08-09 07:21:35 -07:00
committed by GitHub
parent 2433fa213c
commit c70aee247e
937 changed files with 48087 additions and 50044 deletions
@@ -1,21 +0,0 @@
export const managedLabelSpecs: Record<string, { color: string; description: string }>;
export const candidateLabels: {
blankTemplate: string;
lowSignalDocs: string;
docsDiscoverability: string;
testOnlyNoBug: string;
refactorOnly: string;
needsPrContext: string;
dirtyCandidate: string;
riskyInfra: string;
externalPluginCandidate: string;
};
export function classifyPullRequestCandidateLabels(
pullRequest: Record<string, unknown>,
files: Array<{ filename: string; status: string }>,
): string[];
export function runBarnacleAutoResponse(params: {
github: Record<string, unknown>;
context: Record<string, unknown>;
core?: Pick<Console, "info">;
}): Promise<void>;
@@ -77,6 +77,7 @@ const rules = [
},
];
/** @type {Record<string, { color: string; description: string }>} */
export const managedLabelSpecs = {
"r: skill": {
color: "5319E7",
@@ -898,6 +899,13 @@ async function removeLabels(github, context, issueNumber, labels, labelSet) {
}
}
/**
* @param {{
* github: Record<string, unknown>;
* context: Record<string, unknown>;
* core?: Pick<Console, "info">;
* }} params
*/
export async function runBarnacleAutoResponse({ github, context, core = console }) {
const target = context.payload.issue ?? context.payload.pull_request;
if (!target) {
-16
View File
@@ -1,16 +0,0 @@
export function validateDatedTodoReport(
report: string,
options?: { expectedDate?: string; repoRoot?: string },
): void;
export function runDatedTodoUpsert(params: {
github: Record<string, unknown>;
context: { repo: { owner: string; repo: string } };
core: { info: (message: string) => void; warning: (message: string) => void };
dryRun?: boolean;
report?: string;
}): Promise<{
action: "create" | "update";
issueNumber?: number;
addedUrgent: string[];
}>;
-118
View File
@@ -1,118 +0,0 @@
export const GITHUB_API_REQUEST_TIMEOUT_MS: number;
export const GITHUB_ERROR_BODY_MAX_BYTES: number;
export const GITHUB_RESPONSE_BODY_MAX_BYTES: number;
export const dependencyChangedLabel: "dependencies-changed";
type Comment = {
body?: string;
created_at?: string;
html_url?: string;
user?: { login?: string };
};
type PullRequest = {
head?: { ref?: string; repo?: { full_name?: string }; sha?: string };
maintainer_can_modify?: boolean;
user?: { login?: string };
};
type ActorCandidate = { login: string; source: string };
type DependencyGraphChange = {
change_type: string;
manifest?: string | null;
name?: string | null;
};
export function isDependencyFile(filename: string): boolean;
export function isDependencyManifest(filename: string): boolean;
export function isPackageLockfile(filename: string): boolean;
export function dependencyFieldChanges(
baseManifest: Record<string, unknown>,
headManifest: Record<string, unknown>,
): string[];
export function isRemovalOnlyDependencyGraphChange(
changes: readonly DependencyGraphChange[],
): boolean;
export function shouldAutoscrubDependencyLockfiles(options: {
dependencyFiles?: string[];
lockfileChanges: unknown[];
dependencyManifestChanges?: unknown[];
}): boolean;
export function canAutoscrubPullRequest(options: {
owner: string;
repo: string;
pullRequest: PullRequest;
}): boolean;
export function sanitizeDisplayValue(value: unknown): string;
export function markdownCode(value: unknown): string;
export function readBoundedGitHubJson(
response: Response,
maxBytes?: number,
options?: { signal?: AbortSignal },
): Promise<unknown>;
export function findDependencyOverrideCommand(options: {
comments: Comment[];
expectedSha: string;
isSecurityMember: (login: string) => boolean;
newerThan?: string;
}): { login: string; reason: string | null; sha: string; url?: string } | null;
export function findDependencyOverrideCommandAsync(options: {
comments: Comment[];
expectedSha: string;
isSecurityMember: (login: string) => Promise<boolean>;
newerThan: string;
}): Promise<{ login: string; reason: string | null; sha: string; url?: string } | null>;
export function dependencyGuardCommentHeadSha(comment: Comment): string | null;
export function dependencyOverrideExpectedSha(
existingGuardComment: Comment | null,
currentHeadSha: string,
): string | null;
export function isDependencyGuardAuthorizedForHead(
comment: Comment,
currentHeadSha: string,
): boolean;
export function isDependencyGuardTrustedForHead(comment: Comment, currentHeadSha: string): boolean;
export function securityApproverSet(value: unknown): Set<string>;
export function dependencyGuardCommentAuthors(value?: unknown): Set<string>;
export function isDependencyGuardMarkerComment(
comment: Comment,
marker: string,
trustedAuthors: Set<string>,
): boolean;
export function renderAuthorizedDependencyComment(override: Record<string, unknown>): string;
export function renderTrustedDependencyComment(options: {
actor: { login: string; reason: string };
headSha: string;
}): string;
export function renderRemovalOnlyDependencyComment(options: {
dependencyGraphChanges: readonly DependencyGraphChange[];
headSha?: string;
}): string;
export function renderAutoscrubbedDependencyComment(options: {
baseBranch: string;
lockfileChanges: string[];
commitSha: string;
}): string;
export function isAutoscrubbedDependencyComment(comment: Comment): boolean;
export function renderClearedDependencyGuardComment(options: { headSha: string }): string;
export function renderBlockedDependencyComment(options: Record<string, unknown>): string;
export function dependencyGuardTrustedActorCandidates(options: {
pullRequest: PullRequest;
event: Record<string, unknown>;
currentHeadSha: string;
}): ActorCandidate[];
export function findTrustedDependencyGuardActor(options: {
candidates: ActorCandidate[];
isDependencyApprover: (login: string) => Promise<string | null>;
}): Promise<{ login: string; reason: string } | null>;
export function githubApi(
token: string,
options?: {
fetchImpl?: typeof fetch;
responseMaxBodyBytes?: number;
retryDelaysMs?: readonly number[];
timeoutMs?: number;
},
): { request(path: string, options?: Record<string, unknown>): Promise<unknown> };
export function createAutoscrubCommit(...args: unknown[]): Promise<unknown>;
export function readBoundedGitHubErrorText(...args: unknown[]): Promise<string>;
+53
View File
@@ -55,6 +55,21 @@ const dependencyManifestFields = [
"libc",
];
/**
* @typedef {{
* body?: string,
* created_at?: string,
* html_url?: string,
* user?: { login?: string },
* }} GuardComment
* @typedef {{ login: string, source: string }} GuardActorCandidate
* @typedef {{ path: string, fields: string[] }} DependencyManifestChange
* @typedef {{ kind: "not-attempted" } |
* { kind: "blocked-by-dependency-manifest-fields", changes: DependencyManifestChange[] } |
* { kind: "blocked-by-other-dependency-files", files: string[] } |
* { kind: "failed", reason: string }} AutoscrubStatus
*/
export function isDependencyFile(filename) {
return (
filename.endsWith("package-lock.json") ||
@@ -86,6 +101,13 @@ export function isRemovalOnlyDependencyGraphChange(changes) {
return changes.length > 0 && changes.every((change) => change.change_type === "removed");
}
/**
* @param {{
* dependencyFiles?: string[],
* lockfileChanges: string[],
* dependencyManifestChanges?: DependencyManifestChange[],
* }} options
*/
export function shouldAutoscrubDependencyLockfiles({
dependencyFiles = [],
lockfileChanges,
@@ -174,6 +196,14 @@ function* dependencyOverrideCandidates({ comments, expectedSha, newerThan }) {
}
}
/**
* @param {{
* comments: GuardComment[],
* expectedSha: string | null,
* isSecurityMember: (login: string) => boolean,
* newerThan?: string,
* }} options
*/
export function findDependencyOverrideCommand({
comments,
expectedSha,
@@ -188,6 +218,14 @@ export function findDependencyOverrideCommand({
return null;
}
/**
* @param {{
* comments: GuardComment[],
* expectedSha: string | null,
* isSecurityMember: (login: string) => Promise<boolean>,
* newerThan?: string,
* }} input
*/
export async function findDependencyOverrideCommandAsync(input) {
for (const candidate of dependencyOverrideCandidates(input)) {
if (await input.isSecurityMember(candidate.login)) {
@@ -368,6 +406,15 @@ export function renderClearedDependencyGuardComment({ headSha }) {
].join("\n");
}
/**
* @param {{
* baseBranch?: string,
* headSha?: string,
* lockfileChanges: string[],
* dependencyManifestChanges: DependencyManifestChange[],
* autoscrubStatus?: AutoscrubStatus | null,
* }} options
*/
export function renderBlockedDependencyComment({
baseBranch,
headSha,
@@ -462,6 +509,12 @@ export function dependencyGuardTrustedActorCandidates({ pullRequest, event, curr
return guardTrustedActorCandidates({ pullRequest, event, currentHeadSha });
}
/**
* @param {{
* candidates: GuardActorCandidate[],
* isDependencyApprover: (login: string) => Promise<string | null>,
* }} options
*/
export async function findTrustedDependencyGuardActor({ candidates, isDependencyApprover }) {
for (const candidate of candidates) {
const role = await isDependencyApprover(candidate.login);
@@ -165,7 +165,7 @@ fi
# Exact-target reuse still requires internally consistent version stamps
# (for example package.json must agree with the macOS plist).
if ! (cd "$REPO_DIR" && node "$PREFLIGHT" --macos-versions-only >&2); then
if ! (cd "$REPO_DIR" && env -u NODE_OPTIONS node "$PREFLIGHT" --macos-versions-only >&2); then
no_reuse "target version metadata is inconsistent"
fi
-33
View File
@@ -1,33 +0,0 @@
export function classifyPrForSweep(params: {
pr: {
draft?: boolean;
created_at: string;
updated_at: string;
mergeable?: boolean | null;
auto_merge?: object | null;
};
ciRuns: Array<{ conclusion: string | null }>;
botCloseCount: number;
now: number;
}): { action: "refire" | "skip"; reason: string };
export function classifyRunForRevive(params: {
run: {
conclusion: string | null;
event: string;
run_attempt: number;
created_at: string;
head_branch?: string | null;
head_repository?: { full_name?: string };
};
prCreatedAt: string;
prHeadBranch: string;
repoFullName: string;
}): { action: "revive" | "skip"; reason: string };
export function runPrCiSweeper(params: {
github: Record<string, unknown>;
context: Record<string, unknown>;
core: Pick<Console, "info"> & { setFailed: (message: string) => void };
dryRun?: boolean;
appSlug?: string;
now?: number;
}): Promise<Array<{ number: number; sha: string; action: "refire" | "skip"; reason: string }>>;
+47
View File
@@ -35,6 +35,21 @@ const sleep = (ms) =>
setTimeout(resolve, ms);
});
/**
* @param {{
* pr: {
* draft?: boolean;
* created_at: string;
* updated_at: string;
* mergeable?: boolean | null;
* auto_merge?: object | null;
* };
* ciRuns: Array<{ conclusion: string | null }>;
* botCloseCount: number;
* now: number;
* }} params
* @returns {{ action: "refire" | "skip"; reason: string }}
*/
export function classifyPrForSweep({ pr, ciRuns, botCloseCount, now }) {
if (pr.draft) {
return { action: "skip", reason: "draft" };
@@ -69,6 +84,22 @@ export function classifyPrForSweep({ pr, ciRuns, botCloseCount, now }) {
};
}
/**
* @param {{
* run: {
* conclusion: string | null;
* event: string;
* run_attempt: number;
* created_at: string;
* head_branch?: string | null;
* head_repository?: { full_name?: string };
* };
* prCreatedAt: string;
* prHeadBranch: string;
* repoFullName: string;
* }} params
* @returns {{ action: "revive" | "skip"; reason: string }}
*/
export function classifyRunForRevive({ run, prCreatedAt, prHeadBranch, repoFullName }) {
if (run.conclusion !== "cancelled") {
return { action: "skip", reason: "not-cancelled" };
@@ -297,6 +328,22 @@ async function reopenWithRetry({ github, core, owner, repo, pullNumber }) {
return false;
}
/**
* @param {{
* github: Record<string, unknown>;
* context: Record<string, unknown>;
* core: Pick<Console, "info"> & { setFailed: (message: string) => void };
* dryRun?: boolean;
* appSlug?: string;
* now?: number;
* }} params
* @returns {Promise<Array<{
* number: number;
* sha: string;
* action: "refire" | "skip";
* reason: string;
* }>>}
*/
export async function runPrCiSweeper({
github,
context,
@@ -1,38 +0,0 @@
export const PROOF_OVERRIDE_LABEL: "proof: override";
export const PROOF_SUFFICIENT_LABEL: "proof: sufficient";
export const NEEDS_PR_CONTEXT_LABEL: "triage: needs-pr-context";
type PullRequest = Record<string, unknown>;
type Comment = Record<string, unknown>;
type Evaluation = {
status: string;
reason: string;
applies: boolean;
passed: boolean;
missingSections: string[];
};
export function readBoundedGitHubApiJson(
response: Response,
label: string,
maxBytes?: number,
options?: { timeoutMs?: number },
): Promise<unknown>;
export function isMaintainerTeamMember(params?: {
token?: string;
org?: string;
login?: string;
teamSlug?: string;
fetch?: typeof globalThis.fetch;
timeoutMs?: number;
}): Promise<boolean>;
export function hasAuthoredPullRequestSection(heading: string, body?: string): boolean;
export function hasClawSweeperExactHeadProof(params?: {
pullRequest?: PullRequest;
comments?: Comment[];
}): boolean;
export function evaluateClawSweeperExactHeadProof(params?: {
pullRequest?: PullRequest;
comments?: Comment[];
}): Evaluation;
export function evaluatePullRequestContext(params?: { pullRequest?: PullRequest }): Evaluation;
export function labelsForPullRequestContext(evaluation: Evaluation): string[];
+61 -2
View File
@@ -2,6 +2,17 @@
import { readBoundedResponseText } from "../lib/bounded-response.mjs";
import { escapeRegExp } from "../lib/regexp.mjs";
/** @typedef {Record<string, unknown>} PullRequest */
/** @typedef {Record<string, unknown>} Comment */
/**
* @typedef {object} Evaluation
* @property {string} status
* @property {string} reason
* @property {boolean} applies
* @property {boolean} passed
* @property {string[]} missingSections
*/
/** ClawSweeper-owned labels that OpenClaw preserves but does not mutate. */
export const PROOF_OVERRIDE_LABEL = "proof: override";
export const PROOF_SUFFICIENT_LABEL = "proof: sufficient";
@@ -88,6 +99,13 @@ async function withGitHubApiTimeout(label, timeoutMs, run) {
}
}
/**
* @param {Response} response
* @param {string} label
* @param {number} [maxBytes]
* @param {{ timeoutMs?: number }} [options]
* @returns {Promise<unknown>}
*/
export async function readBoundedGitHubApiJson(
response,
label,
@@ -181,6 +199,17 @@ function isExternalPullRequest(pullRequest) {
return !privilegedAuthorAssociations.has(authorAssociation);
}
/**
* @param {{
* token?: string,
* org?: string,
* login?: string,
* teamSlug?: string,
* fetch?: typeof globalThis.fetch,
* timeoutMs?: number,
* }} [params]
* @returns {Promise<boolean>}
*/
export async function isMaintainerTeamMember({
token,
org,
@@ -286,6 +315,10 @@ function extractMarkdownSections(headingRegex, body = "") {
return sections;
}
/**
* @param {string} heading
* @param {string} [body]
*/
export function hasAuthoredPullRequestSection(heading, body = "") {
const headingPattern = new RegExp(`^#{2,6}\\s+${escapeRegExp(heading)}\\b[^\\n]*$`, "im");
return !isMissingValue(extractMarkdownSections(headingPattern, body).at(-1) ?? "");
@@ -361,6 +394,12 @@ function isMissingValue(value) {
return missingValueRegex.test(trimmed);
}
/**
* @param {string} status
* @param {string} reason
* @param {Partial<Evaluation>} [details]
* @returns {Evaluation}
*/
function result(status, reason, details = {}) {
return {
status,
@@ -390,8 +429,16 @@ function isTrustedClawSweeperComment(comment) {
return CLAWSWEEPER_BOT_LOGINS.has(login) && userType === "Bot";
}
/**
* @param {{ pullRequest?: PullRequest, comments?: Comment[] }} [params]
* @returns {boolean}
*/
export function hasClawSweeperExactHeadProof({ pullRequest, comments = [] } = {}) {
const pullNumber = String(pullRequest?.number ?? "");
const rawPullNumber = pullRequest?.number;
const pullNumber =
typeof rawPullNumber === "string" || typeof rawPullNumber === "number"
? String(rawPullNumber)
: "";
const headSha = String(pullRequest?.head?.sha ?? pullRequest?.head_sha ?? "").toLowerCase();
if (!pullNumber || !/^[0-9a-f]{40}$/i.test(headSha)) {
return false;
@@ -401,7 +448,7 @@ export function hasClawSweeperExactHeadProof({ pullRequest, comments = [] } = {}
if (!isTrustedClawSweeperComment(comment)) {
continue;
}
const body = String(comment?.body ?? "");
const body = typeof comment?.body === "string" ? comment.body : "";
const markers = body.match(/<!--\s*clawsweeper-verdict:pass\b[\s\S]*?-->/gi) ?? [];
for (const marker of markers) {
const item = extractMarkerField(marker, "item");
@@ -414,6 +461,10 @@ export function hasClawSweeperExactHeadProof({ pullRequest, comments = [] } = {}
return false;
}
/**
* @param {{ pullRequest?: PullRequest, comments?: Comment[] }} [params]
* @returns {Evaluation}
*/
export function evaluateClawSweeperExactHeadProof({ pullRequest, comments = [] } = {}) {
if (hasClawSweeperExactHeadProof({ pullRequest, comments })) {
return result(
@@ -424,6 +475,10 @@ export function evaluateClawSweeperExactHeadProof({ pullRequest, comments = [] }
return result("insufficient", "No exact-head ClawSweeper proof verdict was found.");
}
/**
* @param {{ pullRequest?: PullRequest }} [params]
* @returns {Evaluation}
*/
export function evaluatePullRequestContext({ pullRequest } = {}) {
if (!isExternalPullRequest(pullRequest)) {
return result("skipped", "Maintainer, collaborator, or bot PRs do not require this gate.");
@@ -456,6 +511,10 @@ export function evaluatePullRequestContext({ pullRequest } = {}) {
return result("passed", "External PR includes problem context and evidence.");
}
/**
* @param {Evaluation} evaluation
* @returns {string[]}
*/
export function labelsForPullRequestContext(evaluation) {
if (evaluation.status === "missing" || evaluation.status === "insufficient") {
return [NEEDS_PR_CONTEXT_LABEL];
@@ -1,81 +0,0 @@
export const GITHUB_API_REQUEST_TIMEOUT_MS: number;
export const GITHUB_ERROR_BODY_MAX_BYTES: number;
export const GITHUB_RESPONSE_BODY_MAX_BYTES: number;
export const allowSecuritySensitiveCommand: string;
export const securitySensitiveGuardMarker: string;
type Comment = { body?: string; created_at?: string; html_url?: string; user?: { login?: string } };
type ActorCandidate = { login: string; source: string };
export function securitySensitiveFileDefinitions(): Array<{ path: string; reason: string }>;
export function securitySensitiveFileDefinition(
filename: string,
): { path: string; reason: string } | undefined;
export function isSecuritySensitiveFile(filename: string): boolean;
export function sanitizeDisplayValue(value: unknown): string;
export function markdownCode(value: unknown): string;
export function findSecuritySensitiveOverrideCommand(options: {
comments: Comment[];
expectedSha: string;
isSecurityMember: (login: string) => boolean;
newerThan?: string;
}): { login: string; reason: string | null; sha: string; url?: string } | null;
export function findSecuritySensitiveOverrideCommandAsync(options: {
comments: Comment[];
expectedSha: string;
isSecurityMember: (login: string) => Promise<boolean>;
newerThan?: string;
}): Promise<{ login: string; reason: string | null; sha: string; url?: string } | null>;
export function securitySensitiveGuardCommentHeadSha(comment: Comment): string | null;
export function securitySensitiveOverrideExpectedSha(
comment: Comment | null,
currentHeadSha: string,
): string | null;
export function isSecuritySensitiveGuardAuthorizedForHead(
comment: Comment,
currentHeadSha: string,
): boolean;
export function isSecuritySensitiveGuardTrustedForHead(
comment: Comment,
currentHeadSha: string,
): boolean;
export function securityApproverSet(value: unknown): Set<string>;
export function securitySensitiveGuardCommentAuthors(value?: unknown): Set<string>;
export function isSecuritySensitiveGuardMarkerComment(
comment: Comment,
trustedAuthors: Set<string>,
): boolean;
export function collectSecuritySensitiveChanges(
files: Array<{ filename: string; previous_filename?: string; status?: string }>,
): Array<Record<string, string>>;
export function renderSecuritySensitiveAwarenessComment(
changes: Array<Record<string, string>>,
): string;
export function renderAuthorizedSecuritySensitiveComment(override: Record<string, unknown>): string;
export function renderTrustedSecuritySensitiveComment(options: Record<string, unknown>): string;
export function renderClearedSecuritySensitiveGuardComment(options: { headSha: string }): string;
export function renderBlockedSecuritySensitiveComment(options: Record<string, unknown>): string;
export function securitySensitiveGuardTrustedActorCandidates(
options: Record<string, unknown>,
): ActorCandidate[];
export function findTrustedSecuritySensitiveGuardActor(options: {
candidates: ActorCandidate[];
isSecuritySensitiveApprover: (login: string) => Promise<string | null>;
}): Promise<{ login: string; reason: string } | null>;
export function githubApi(
token: string,
options?: {
fetchImpl?: typeof fetch;
responseMaxBodyBytes?: number;
retryDelaysMs?: readonly number[];
timeoutMs?: number;
},
): { request(path: string, options?: Record<string, unknown>): Promise<unknown> };
export function readBoundedGitHubErrorText(
response: Response,
maxBytes?: number,
options?: { signal?: AbortSignal },
): Promise<string>;
export function readBoundedGitHubJson(
response: Response,
maxBytes?: number,
options?: { signal?: AbortSignal },
): Promise<unknown>;
@@ -39,6 +39,16 @@ const securitySensitiveFiles = [
},
];
/**
* @typedef {{
* body?: string,
* created_at?: string,
* html_url?: string,
* user?: { login?: string },
* }} GuardComment
* @typedef {{ login: string, source: string }} GuardActorCandidate
*/
export function securitySensitiveFileDefinitions() {
return securitySensitiveFiles.map((entry) => ({ ...entry }));
}
@@ -84,6 +94,14 @@ function* securitySensitiveOverrideCandidates({ comments, expectedSha, newerThan
}
}
/**
* @param {{
* comments: GuardComment[],
* expectedSha: string | null,
* isSecurityMember: (login: string) => boolean,
* newerThan?: string,
* }} options
*/
export function findSecuritySensitiveOverrideCommand({
comments,
expectedSha,
@@ -102,6 +120,14 @@ export function findSecuritySensitiveOverrideCommand({
return null;
}
/**
* @param {{
* comments: GuardComment[],
* expectedSha: string | null,
* isSecurityMember: (login: string) => Promise<boolean>,
* newerThan?: string,
* }} input
*/
export async function findSecuritySensitiveOverrideCommandAsync(input) {
for (const candidate of securitySensitiveOverrideCandidates(input)) {
if (await input.isSecurityMember(candidate.login)) {
@@ -304,6 +330,12 @@ export function securitySensitiveGuardTrustedActorCandidates({
return guardTrustedActorCandidates({ pullRequest, event, currentHeadSha });
}
/**
* @param {{
* candidates: GuardActorCandidate[],
* isSecuritySensitiveApprover: (login: string) => Promise<string | null>,
* }} options
*/
export async function findTrustedSecuritySensitiveGuardActor({
candidates,
isSecuritySensitiveApprover,