Skip to content

Commit 2e2366b

Browse files
authored
chore(tooling): typecheck scripts/** with a dedicated tsgo lane (#104348)
* feat(tooling): add tsgo typecheck lane for scripts/** * fix(scripts): burn down scripts type debt surfaced by the new lane Typing-only except bugs the lane surfaced: gh-read timeout race, Discord Headers spread dropping entries, undefined allowedHeadBranches match, plugin-boundary matchAll crash. Deletes retired config keys from fixtures/benches (prompt snapshots regenerated, config dump only) and the orphaned non-runnable sync-moonshot-docs script. Adds full-surface .d.mts declarations for existing .mjs boundaries.
1 parent 6e81c54 commit 2e2366b

52 files changed

Lines changed: 1162 additions & 536 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,6 +1348,7 @@ jobs:
13481348
;;
13491349
test-types)
13501350
pnpm check:test-types
1351+
pnpm tsgo:scripts
13511352
;;
13521353
*)
13531354
echo "Unsupported check task: $TASK" >&2

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1962,6 +1962,7 @@
19621962
"tsgo:extensions:test": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo",
19631963
"tsgo:prod": "pnpm tsgo:core && pnpm tsgo:extensions",
19641964
"tsgo:profile": "node scripts/profile-tsgo.mjs",
1965+
"tsgo:scripts": "node scripts/run-tsgo.mjs -p tsconfig.scripts.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/scripts.tsbuildinfo",
19651966
"tsgo:test": "pnpm tsgo:core:test && pnpm tsgo:extensions:test",
19661967
"tsgo:test:extensions": "pnpm tsgo:extensions:test",
19671968
"tsgo:test:packages": "node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.packages.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-packages.tsbuildinfo",

scripts/android-app-i18n.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export async function checkAndroidAppI18n() {
6565
]);
6666
const [base, ...translations] = localeStrings;
6767
const baseKeys = new Set(base.keys());
68-
const problems = translations.flatMap((strings, index) => {
68+
const problems: Array<readonly [string, string[]]> = translations.flatMap((strings, index) => {
6969
const locale = NATIVE_I18N_LOCALES[index];
7070
const keys = new Set(strings.keys());
7171
const placeholderMismatches = [...base].flatMap(([key, sourceValue]) => {

scripts/anthropic-prompt-probe.ts

Lines changed: 21 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -212,17 +212,16 @@ function listSetupTokenProfiles(
212212
store: { profiles: Record<string, AuthProfileCredential> },
213213
normalizeProviderId: (provider: string) => string,
214214
): Array<{ id: string; token: string }> {
215-
return Object.entries(store.profiles)
216-
.filter(([, cred]) => {
217-
if (cred.type !== "token") {
218-
return false;
219-
}
220-
if (normalizeProviderId(cred.provider) !== "anthropic") {
221-
return false;
222-
}
223-
return isSetupToken(cred.token ?? "");
224-
})
225-
.map(([id, cred]) => ({ id, token: cred.token ?? "" }));
215+
return Object.entries(store.profiles).flatMap(([id, cred]) => {
216+
if (
217+
cred.type !== "token" ||
218+
normalizeProviderId(cred.provider) !== "anthropic" ||
219+
!isSetupToken(cred.token ?? "")
220+
) {
221+
return [];
222+
}
223+
return [{ id, token: cred.token ?? "" }];
224+
});
226225
}
227226

228227
function pickSetupTokenProfile(candidates: Array<{ id: string; token: string }>): {
@@ -390,15 +389,16 @@ async function startAnthropicProxy(params: { port: number; upstreamBaseUrl: stri
390389
}
391390
headers.set(key, Array.isArray(value) ? value.join(", ") : value);
392391
}
393-
const upstreamRes = await fetch(upstreamUrl, {
392+
const upstreamInit = {
394393
method,
395394
headers,
396395
body:
397396
method === "GET" || method === "HEAD" || requestBody.byteLength === 0
398397
? undefined
399-
: requestBody,
398+
: Uint8Array.from(requestBody),
400399
duplex: "half",
401-
});
400+
} as RequestInit & { duplex: "half" };
401+
const upstreamRes = await fetch(upstreamUrl, upstreamInit);
402402
const responseHeaders: Record<string, string> = {};
403403
for (const [key, value] of upstreamRes.headers.entries()) {
404404
const lower = key.toLowerCase();
@@ -926,19 +926,21 @@ async function runGatewayPrompt(prompt: string): Promise<PromptResult> {
926926
mode: "cli",
927927
});
928928
const text = extractPayloadText(waitRes);
929+
const waitStatus = typeof waitRes.status === "string" ? waitRes.status : undefined;
930+
const waitError = typeof waitRes.error === "string" ? waitRes.error : undefined;
929931
const logTail = await readLogTail(logPath);
930-
const matched400 = matchesExtraUsage400(waitRes.error, logTail, JSON.stringify(waitRes));
932+
const matched400 = matchesExtraUsage400(waitError, logTail, JSON.stringify(waitRes));
931933
return {
932934
prompt,
933-
ok: waitRes.status === "ok" && !matched400,
935+
ok: waitStatus === "ok" && !matched400,
934936
transport: "gateway",
935937
promptMode: GATEWAY_PROMPT_MODE,
936-
status: waitRes.status,
938+
status: waitStatus,
937939
text: text || undefined,
938940
error:
939-
waitRes.status === "ok"
941+
waitStatus === "ok"
940942
? undefined
941-
: redactForDevToolLog(waitRes.error || logTail || "agent.wait failed"),
943+
: redactForDevToolLog(waitError || logTail || "agent.wait failed"),
942944
matchedExtraUsage400: matched400,
943945
capture: summarizeCapture(proxy?.getLastCapture(), prompt),
944946
...promptProbeTmpResult(tmpDir),

scripts/apple-app-i18n.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,12 @@ const LOCALIZED_WRAPPER_CONTRACTS: Record<string, string[]> = {
2424
],
2525
};
2626

27-
const CATALOGS = [
27+
type AppleCatalogSpec = {
28+
path: string;
29+
coverage: Record<string, readonly string[]>;
30+
};
31+
32+
const CATALOGS: readonly AppleCatalogSpec[] = [
2833
{
2934
path: "apps/ios/Resources/Localizable.xcstrings",
3035
coverage: {
@@ -99,7 +104,7 @@ const CATALOGS = [
99104
"apps/macos/Sources/OpenClaw/CronSettings+Rows.swift": ["Run now"],
100105
},
101106
},
102-
] as const;
107+
];
103108

104109
type Catalog = {
105110
sourceLanguage?: string;

scripts/bench-model.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ async function main(argv = process.argv.slice(2)): Promise<void> {
182182
name: "Claude Opus 4.6",
183183
api: "anthropic-messages",
184184
provider: "anthropic",
185+
baseUrl: "https://api.anthropic.com",
185186
reasoning: true,
186187
input: ["text", "image"],
187188
cost: { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },

scripts/bench-sqlite-state.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import fs from "node:fs";
33
import os from "node:os";
44
import path from "node:path";
5-
import type { DatabaseSync } from "node:sqlite";
5+
import type { DatabaseSync, SQLInputValue } from "node:sqlite";
66
import { pathToFileURL } from "node:url";
77
import {
88
openOpenClawAgentDatabase,
@@ -465,7 +465,7 @@ function percentile(values: number[], pct: number): number {
465465
function runTimedQuery(
466466
db: DatabaseSync,
467467
query: string,
468-
params: unknown[],
468+
params: SQLInputValue[],
469469
runs: number,
470470
): TimedQuery {
471471
const statement = db.prepare(query);

scripts/bench-web-fetch.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,12 @@ const TEXT_BODY = "OpenClaw web_fetch direct text benchmark body.".repeat(160);
114114
const MARKDOWN_BODY = "# Web Fetch Benchmark\n\n" + "- markdown list item\n".repeat(220);
115115
const OFFLINE_PROVIDER_ENV_VARS = ["FIRECRAWL_API_KEY"] as const;
116116

117-
const lookupFn: LookupFn = async () => [{ address: "93.184.216.34", family: 4 }];
117+
const lookupFn = (async () => [{ address: "93.184.216.34", family: 4 }]) as unknown as LookupFn;
118118
const toolConfig: OpenClawConfig = {
119119
tools: {
120120
web: {
121121
fetch: {
122122
cacheTtlMinutes: 0,
123-
firecrawl: { enabled: false },
124123
},
125124
},
126125
},
@@ -270,7 +269,7 @@ function installMockFetch(params: { body: string; contentType: string }) {
270269
headers: {
271270
"content-type": params.contentType,
272271
},
273-
})) as typeof globalThis.fetch & { mock: object };
272+
})) as unknown as typeof globalThis.fetch & { mock: object };
274273
// fetchWithSsrFGuard preserves dispatcher support unless global fetch is a
275274
// test double. The marker keeps this benchmark offline and deterministic.
276275
fetchImpl.mock = {};

scripts/changed-lanes.mjs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ const DOCS_PATH_RE = /^(?:docs\/|README\.md$|AGENTS\.md$|.*\.mdx?$)/u;
1313
const APP_PATH_RE = /^(?:apps\/|Swabble\/|appcast\.xml$)/u;
1414
const EXTENSION_PATH_RE = /^extensions\/[^/]+(?:\/|$)/u;
1515
const CORE_PATH_RE = /^(?:src\/|ui\/|packages\/)/u;
16+
const SCRIPTS_TYPECHECK_PATH_RE =
17+
/^(?:scripts\/.*\.(?:[cm]?ts|[cm]?tsx)|tsconfig\.scripts\.json)$/u;
1618
const TOOLING_PATH_RE =
1719
/^(?:scripts\/|test\/vitest\/|\.github\/|\.vscode\/|config\/|deploy\/|git-hooks\/|Dockerfile\.sandbox(?:-(?:browser|common))?$|Makefile$|docker-setup\.sh$|setup-podman\.sh$|openclaw\.podman\.env$|skills\/pyproject\.toml$|vitest(?:\..+)?\.config\.ts$|tsconfig.*\.json$|\.dockerignore$|\.gitignore$|\.jscpd\.json$|\.npmignore$|\.pre-commit-config\.yaml$|\.swiftformat$|\.swiftlint\.yml$|\.oxlint.*|\.oxfmt.*)/u;
1820
const ROOT_GLOBAL_PATH_RE =
@@ -54,7 +56,7 @@ export const RELEASE_METADATA_PATHS = new Set([
5456
"package.json",
5557
]);
5658

57-
/** @typedef {"core" | "coreTests" | "extensions" | "extensionTests" | "apps" | "docs" | "tooling" | "liveDockerTooling" | "releaseMetadata" | "all"} ChangedLane */
59+
/** @typedef {"core" | "coreTests" | "extensions" | "extensionTests" | "scripts" | "apps" | "docs" | "tooling" | "liveDockerTooling" | "releaseMetadata" | "all"} ChangedLane */
5860

5961
/**
6062
* @typedef {{
@@ -85,6 +87,7 @@ export function createEmptyChangedLanes() {
8587
coreTests: false,
8688
extensions: false,
8789
extensionTests: false,
90+
scripts: false,
8891
apps: false,
8992
docs: false,
9093
tooling: false,
@@ -139,6 +142,10 @@ export function detectChangedLanes(changedPaths, options = {}) {
139142
}
140143

141144
for (const changedPath of paths) {
145+
if (SCRIPTS_TYPECHECK_PATH_RE.test(changedPath)) {
146+
lanes.scripts = true;
147+
}
148+
142149
if (DOCS_PATH_RE.test(changedPath)) {
143150
lanes.docs = true;
144151
continue;

scripts/check-changed.mjs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -391,6 +391,9 @@ export function createChangedCheckPlan(result, options = {}) {
391391
if (lanes.extensionTests) {
392392
addTypecheck("typecheck extension tests", ["tsgo:extensions:test"]);
393393
}
394+
if (lanes.scripts) {
395+
addTypecheck("typecheck scripts", ["tsgo:scripts"]);
396+
}
394397

395398
if (lanes.core || lanes.coreTests) {
396399
const coreLintCommand = createTargetedCoreLintCommand(result.paths, baseEnv);

0 commit comments

Comments
 (0)