lint: enable small oxlint rules

This commit is contained in:
Peter Steinberger
2026-04-11 02:10:14 +01:00
parent ce87edbad4
commit 39d1a817fa
41 changed files with 144 additions and 151 deletions

View File

@@ -113,7 +113,7 @@ export async function serveAcpGateway(opts: AcpServerOptions = {}): Promise<void
const output = Readable.toWeb(process.stdin) as unknown as ReadableStream<Uint8Array>;
const stream = ndJsonStream(input, output);
new AgentSideConnection((conn: AgentSideConnection) => {
const _connection = new AgentSideConnection((conn: AgentSideConnection) => {
agent = new AcpGatewayAgent(conn, gateway, opts);
agent.start();
return agent;

View File

@@ -330,7 +330,10 @@ describe("acp translator stop reason mapping", () => {
await Promise.resolve();
agent.handleGatewayDisconnect("1006: first disconnect");
agent.handleGatewayReconnect();
for (let attempt = 0; attempt < 5 && !resolveAgentWait; attempt += 1) {
for (let attempt = 0; attempt < 5; attempt += 1) {
if (resolveAgentWait) {
break;
}
await Promise.resolve();
}
expect(resolveAgentWait).toBeDefined();

View File

@@ -539,10 +539,10 @@ describe("spawnAcpDirect", () => {
expect(accepted.childSessionKey).toMatch(/^agent:codex:acp:/);
expect(accepted.runId).toBe("run-1");
expect(accepted.mode).toBe("session");
const patchCalls = hoisted.callGatewayMock.mock.calls
const patchCall = hoisted.callGatewayMock.mock.calls
.map((call: unknown[]) => call[0] as { method?: string; params?: Record<string, unknown> })
.filter((request) => request.method === "sessions.patch");
expect(patchCalls[0]?.params).toMatchObject({
.find((request) => request.method === "sessions.patch");
expect(patchCall?.params).toMatchObject({
key: accepted.childSessionKey,
spawnedBy: "agent:main:main",
});

View File

@@ -758,12 +758,13 @@ function shouldFailClosedInterpreterPreflight(command: string): {
const rawArgv = splitShellArgs(raw);
const argv = rawArgv ? stripPreflightEnvPrefix(rawArgv) : null;
let commandIdx = 0;
while (
argv &&
commandIdx < argv.length &&
/^[A-Za-z_][A-Za-z0-9_]*=.*$/u.test(argv[commandIdx])
) {
commandIdx += 1;
if (argv) {
while (
commandIdx < argv.length &&
/^[A-Za-z_][A-Za-z0-9_]*=.*$/u.test(argv[commandIdx] ?? "")
) {
commandIdx += 1;
}
}
const directExecutable = normalizeOptionalLowercaseString(argv?.[commandIdx]);
const args = argv ? argv.slice(commandIdx + 1) : [];

View File

@@ -25,8 +25,7 @@ function buildLiveAnthropicModel(): {
const modelId =
(process.env.OPENCLAW_LIVE_ANTHROPIC_CACHE_MODEL || "claude-sonnet-4-6")
.split(/[/:]/)
.filter(Boolean)
.pop() || "claude-sonnet-4-6";
.findLast(Boolean) || "claude-sonnet-4-6";
return {
apiKey,
model: {

View File

@@ -759,7 +759,7 @@ export async function runEmbeddedPiAgent(
incompleteTurnText,
});
if (resolveReplayInvalidForAttempt(null)) {
accumulatedReplayState = { ...accumulatedReplayState, replayInvalid: true };
accumulatedReplayState.replayInvalid = true;
}
accumulatedReplayState = observeReplayMetadata(
accumulatedReplayState,

View File

@@ -323,27 +323,27 @@ export function sanitizeConfiguredModelProviderRequest(
export function mergeProviderRequestOverrides(
...overrides: Array<ProviderRequestTransportOverrides | undefined>
): ProviderRequestTransportOverrides | undefined {
let merged: ProviderRequestTransportOverrides | undefined;
const merged: ProviderRequestTransportOverrides = {};
let hasMerged = false;
for (const current of overrides) {
if (!current) {
continue;
}
merged = {
...merged,
...(current.headers
? {
headers: {
...merged?.headers,
...current.headers,
},
}
: {}),
...(current.auth ? { auth: current.auth } : {}),
...(current.proxy ? { proxy: current.proxy } : {}),
...(current.tls ? { tls: current.tls } : {}),
};
hasMerged = true;
if (current.headers) {
merged.headers = Object.assign({}, merged.headers, current.headers);
}
if (current.auth) {
merged.auth = current.auth;
}
if (current.proxy) {
merged.proxy = current.proxy;
}
if (current.tls) {
merged.tls = current.tls;
}
}
return merged;
return hasMerged ? merged : undefined;
}
export function mergeModelProviderRequestOverrides(
@@ -354,10 +354,8 @@ export function mergeModelProviderRequestOverrides(
);
for (const current of overrides) {
if (current?.allowPrivateNetwork !== undefined) {
merged = {
...merged,
allowPrivateNetwork: current.allowPrivateNetwork,
};
merged ??= {};
merged.allowPrivateNetwork = current.allowPrivateNetwork;
}
}
return merged;

View File

@@ -95,14 +95,14 @@ function fileNameFromPathLike(pathLike: string): string | undefined {
try {
const url = new URL(value);
const candidate = url.pathname.split("/").filter(Boolean).at(-1);
const candidate = url.pathname.split("/").findLast(Boolean);
return candidate && candidate.length > 0 ? candidate : undefined;
} catch {
// Not a URL; continue with path-like parsing.
}
const normalized = value.replaceAll("\\", "/");
const candidate = normalized.split("/").filter(Boolean).at(-1);
const candidate = normalized.split("/").findLast(Boolean);
return candidate && candidate.length > 0 ? candidate : undefined;
}

View File

@@ -77,7 +77,7 @@ async function resolveContextReport(
export async function buildContextReply(params: HandleCommandsParams): Promise<ReplyPayload> {
const args = parseContextArgs(params.command.commandBodyNormalized);
const sub = normalizeLowercaseStringOrEmpty(args.split(/\s+/).filter(Boolean)[0]);
const sub = normalizeLowercaseStringOrEmpty(args.split(/\s+/).find(Boolean));
if (!sub || sub === "help") {
return {

View File

@@ -85,7 +85,10 @@ function parseExecDirectiveArgs(raw: string): Omit<
return { key, value };
};
while (i < len) {
for (;;) {
if (i >= len) {
break;
}
const token = takeToken();
if (!token) {
break;

View File

@@ -65,7 +65,10 @@ function parseQueueDirectiveArgs(raw: string): {
i = res.nextIndex;
return res.token;
};
while (i < len) {
for (;;) {
if (i >= len) {
break;
}
const token = takeToken();
if (!token) {
break;

View File

@@ -291,9 +291,12 @@ describe("initSessionState thread forking", () => {
if (!newSessionFile) {
throw new Error("Missing session file for forked thread");
}
const [headerLine] = (await fs.readFile(newSessionFile, "utf-8"))
const headerLine = (await fs.readFile(newSessionFile, "utf-8"))
.split(/\r?\n/)
.filter((line) => line.trim().length > 0);
.find((line) => line.trim().length > 0);
if (!headerLine) {
throw new Error("Missing session header");
}
const parsedHeader = JSON.parse(headerLine) as {
parentSession?: string;
};
@@ -522,7 +525,10 @@ describe("initSessionState thread forking", () => {
expect(result.sessionEntry.forkedFromParent).toBe(true);
expect(result.sessionEntry.sessionFile).toBeTruthy();
const forkedContent = await fs.readFile(result.sessionEntry.sessionFile ?? "", "utf-8");
const [headerLine] = forkedContent.split(/\r?\n/).filter((line) => line.trim().length > 0);
const headerLine = forkedContent.split(/\r?\n/).find((line) => line.trim().length > 0);
if (!headerLine) {
throw new Error("Missing session header");
}
const parsedHeader = JSON.parse(headerLine) as { parentSession?: string };
const expectedParentSession = await fs.realpath(parentSessionFile);
const actualParentSession = parsedHeader.parentSession

View File

@@ -19,16 +19,10 @@ export function resolveCliCommandPathPolicy(commandPath: string[]): CliCommandPa
if (!matchesCommandPath(commandPath, entry.commandPath, { exact: entry.exact })) {
continue;
}
resolvedPolicy = {
...resolvedPolicy,
...entry.policy,
};
Object.assign(resolvedPolicy, entry.policy);
}
if (isGatewayConfigBypassCommandPath(commandPath)) {
resolvedPolicy = {
...resolvedPolicy,
bypassConfigGuard: true,
};
resolvedPolicy.bypassConfigGuard = true;
}
return resolvedPolicy;
}

View File

@@ -67,12 +67,11 @@ export async function removeChannelConfigWizard(
const nextChannels: Record<string, unknown> = { ...next.channels };
delete nextChannels[channel];
next = {
...next,
channels: Object.keys(nextChannels).length
? (nextChannels as OpenClawConfig["channels"])
: undefined,
};
if (Object.keys(nextChannels).length) {
next.channels = nextChannels as OpenClawConfig["channels"];
} else {
delete next.channels;
}
note(
[`${label} removed from config.`, "Note: credentials/sessions on disk are unchanged."].join(

View File

@@ -75,11 +75,12 @@ function normalizeSnippet(raw: string | undefined, fallback: string): string {
}
function firstParagraph(text: string): string {
const parts = text
.split(/\n\s*\n/)
.map((chunk) => chunk.trim())
.filter(Boolean);
return parts[0] ?? "";
return (
text
.split(/\n\s*\n/)
.map((chunk) => chunk.trim())
.find(Boolean) ?? ""
);
}
function parseSearchOutput(raw: string): DocResult[] {

View File

@@ -446,12 +446,7 @@ async function promptBaseUrlAndKey(params: {
initialValue: params.initialBaseUrl ?? OLLAMA_DEFAULT_BASE_URL,
placeholder: "https://api.example.com/v1",
validate: (val) => {
try {
new URL(val);
return undefined;
} catch {
return "Please enter a valid URL (e.g. http://...)";
}
return URL.canParse(val) ? undefined : "Please enter a valid URL (e.g. http://...)";
},
});
const baseUrl = baseUrlInput.trim();
@@ -608,9 +603,7 @@ export function parseNonInteractiveCustomApiFlags(
export function applyCustomApiConfig(params: ApplyCustomApiConfigParams): CustomApiResult {
const baseUrl = normalizeOptionalString(params.baseUrl) ?? "";
try {
new URL(baseUrl);
} catch {
if (!URL.canParse(baseUrl)) {
throw new CustomApiError("invalid_base_url", "Custom provider base URL must be a valid URL.");
}

View File

@@ -87,8 +87,7 @@ describe("config observe recovery", () => {
const lines = (await fsp.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean);
const observe = lines
.map((line) => JSON.parse(line) as Record<string, unknown>)
.filter((line) => line.event === "config.observe")
.at(-1);
.findLast((line) => line.event === "config.observe");
expect(observe?.restoredFromBackup).toBe(true);
expect(observe?.suspicious).toEqual(
expect.arrayContaining(["gateway-mode-missing-vs-last-good", "update-channel-only-root"]),
@@ -154,8 +153,7 @@ describe("config observe recovery", () => {
const lines = (await fsp.readFile(auditPath, "utf-8")).trim().split("\n").filter(Boolean);
const observe = lines
.map((line) => JSON.parse(line) as Record<string, unknown>)
.filter((line) => line.event === "config.observe")
.at(-1);
.findLast((line) => line.event === "config.observe");
expect(observe?.backupHash).toBeTypeOf("string");
expect(observe?.lastKnownGoodIno ?? null).toBeNull();
});

View File

@@ -53,11 +53,7 @@ function flattenUnionSchema(raw: Record<string, unknown>): Record<string, unknow
}
const required =
requiredSets.length > 0
? [
...requiredSets.reduce(
(left, right) => new Set([...left].filter((key) => right.has(key))),
),
]
? [...(requiredSets[0] ?? [])].filter((key) => requiredSets.every((set) => set.has(key)))
: [];
const { anyOf: _anyOf, oneOf: _oneOf, ...rest } = raw;
return { ...rest, type: "object", properties: mergedProps, required };

View File

@@ -389,7 +389,10 @@ describe("node.invoke approval bypass", () => {
idempotencyKey: crypto.randomUUID(),
});
expect(invoke.ok).toBe(true);
for (let i = 0; i < 100 && !lastInvokeParams; i += 1) {
for (let i = 0; i < 100; i += 1) {
if (lastInvokeParams) {
break;
}
await sleep(50);
}
expect(lastInvokeParams).toBeTruthy();

View File

@@ -306,6 +306,6 @@ describe("bonjour-discovery", () => {
});
expect(calls.filter((c) => c[1] === "-B")).toHaveLength(1);
expect(calls.filter((c) => c[1] === "-B")[0]?.[3]).toBe("local.");
expect(calls.find((c) => c[1] === "-B")?.[3]).toBe("local.");
});
});

View File

@@ -138,8 +138,7 @@ function parsePinnedIdentity(stdout: string): FileIdentityStat {
.trim()
.split(/\r?\n/)
.map((value) => value.trim())
.filter(Boolean)
.at(-1);
.findLast(Boolean);
if (!line) {
throw new Error("Pinned write helper returned no identity");
}

View File

@@ -225,8 +225,11 @@ describe("drainPendingDeliveries for WhatsApp reconnect", () => {
// Fail it so it matches the "no listener" filter
const pending = fs
.readdirSync(path.join(tmpDir, "delivery-queue"))
.filter((f) => f.endsWith(".json"));
const entryPath = path.join(tmpDir, "delivery-queue", pending[0]);
.find((f) => f.endsWith(".json"));
if (!pending) {
throw new Error("Missing pending delivery entry");
}
const entryPath = path.join(tmpDir, "delivery-queue", pending);
const entry = JSON.parse(fs.readFileSync(entryPath, "utf-8"));
entry.lastError = "No active WhatsApp Web listener";
entry.retryCount = 1;

View File

@@ -98,8 +98,7 @@ function redactMatch(match: string, groups: string[]): string {
if (match.includes("PRIVATE KEY-----")) {
return redactPemBlock(match);
}
const token =
groups.filter((value) => typeof value === "string" && value.length > 0).at(-1) ?? match;
const token = groups.findLast((value) => typeof value === "string" && value.length > 0) ?? match;
const masked = maskToken(token);
if (token === match) {
return masked;

View File

@@ -1,6 +1,6 @@
export function isValidTimeZone(tz: string): boolean {
try {
new Intl.DateTimeFormat("en", { timeZone: tz });
new Intl.DateTimeFormat("en", { timeZone: tz }).format();
return true;
} catch {
return false;

View File

@@ -37,14 +37,9 @@ function getAjv(mode: "default" | "defaults"): AjvLike {
instance.addFormat("uri", {
type: "string",
validate: (value: string) => {
try {
// Accept absolute URIs so generated config schemas can keep JSON Schema
// `format: "uri"` without noisy AJV warnings during validation/build.
new URL(value);
return true;
} catch {
return false;
}
// Accept absolute URIs so generated config schemas can keep JSON Schema
// `format: "uri"` without noisy AJV warnings during validation/build.
return URL.canParse(value);
},
});
ajvSingletons.set(mode, instance);

View File

@@ -85,14 +85,14 @@ export function applyExclusiveSlotSelection(params: {
}
const warnings: string[] = [];
let pluginsConfig = params.config.plugins ?? {};
const pluginsConfig = params.config.plugins ?? {};
let anyChanged = false;
let entries = { ...pluginsConfig.entries };
let slots = { ...pluginsConfig.slots };
const entries = { ...pluginsConfig.entries };
const slots = { ...pluginsConfig.slots };
for (const slotKey of slotKeys) {
const prevSlot = slots[slotKey];
slots = { ...slots, [slotKey]: params.selectedId };
slots[slotKey] = params.selectedId;
const inferredPrevSlot = prevSlot ?? defaultSlotIdForKey(slotKey);
if (inferredPrevSlot && inferredPrevSlot !== params.selectedId) {
@@ -123,10 +123,7 @@ export function applyExclusiveSlotSelection(params: {
}
const entry = entries[plugin.id];
if (!entry || entry.enabled !== false) {
entries = {
...entries,
[plugin.id]: { ...entry, enabled: false },
};
entries[plugin.id] = { ...entry, enabled: false };
disabledIds.push(plugin.id);
}
}