mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-04 14:44:08 +00:00
chore(lint): enable more readability rules
This commit is contained in:
@@ -32,11 +32,13 @@
|
||||
"eslint/no-useless-computed-key": "error",
|
||||
"eslint/no-useless-concat": "error",
|
||||
"eslint/no-useless-constructor": "error",
|
||||
"eslint/no-useless-rename": "error",
|
||||
"eslint/no-unused-vars": "off",
|
||||
"eslint/no-warning-comments": "error",
|
||||
"eslint/no-unmodified-loop-condition": "error",
|
||||
"eslint/no-new-wrappers": "error",
|
||||
"eslint/no-else-return": "error",
|
||||
"eslint/no-lonely-if": "error",
|
||||
"eslint/no-case-declarations": "error",
|
||||
"eslint/default-case-last": "error",
|
||||
"eslint/default-param-last": "error",
|
||||
@@ -89,6 +91,7 @@
|
||||
"typescript/prefer-namespace-keyword": "error",
|
||||
"typescript/prefer-return-this-type": "error",
|
||||
"typescript/prefer-find": "error",
|
||||
"typescript/prefer-for-of": "error",
|
||||
"typescript/prefer-function-type": "error",
|
||||
"typescript/prefer-includes": "error",
|
||||
"typescript/prefer-reduce-type-parameter": "error",
|
||||
@@ -118,6 +121,7 @@
|
||||
"unicorn/prefer-date-now": "error",
|
||||
"unicorn/prefer-dom-node-text-content": "error",
|
||||
"unicorn/prefer-keyboard-event-key": "error",
|
||||
"unicorn/prefer-array-flat": "error",
|
||||
"unicorn/prefer-array-some": "error",
|
||||
"unicorn/prefer-math-min-max": "error",
|
||||
"unicorn/prefer-node-protocol": "error",
|
||||
|
||||
@@ -373,8 +373,7 @@ function splitExecLine(line: string): string[] {
|
||||
let current = "";
|
||||
let inQuotes = false;
|
||||
let quoteChar = "";
|
||||
for (let i = 0; i < line.length; i += 1) {
|
||||
const ch = line[i];
|
||||
for (const ch of line) {
|
||||
if ((ch === '"' || ch === "'") && (!inQuotes || ch === quoteChar)) {
|
||||
if (inQuotes) {
|
||||
inQuotes = false;
|
||||
|
||||
@@ -2051,10 +2051,8 @@ export class MatrixClient {
|
||||
this.emitter.emit("room.event", roomId, raw);
|
||||
if (isEncryptedEvent) {
|
||||
this.emitter.emit("room.encrypted_event", roomId, raw);
|
||||
} else {
|
||||
if (decryptBridge.shouldEmitUnencryptedMessage(roomId, raw.event_id)) {
|
||||
this.emitter.emit("room.message", roomId, raw);
|
||||
}
|
||||
} else if (decryptBridge.shouldEmitUnencryptedMessage(roomId, raw.event_id)) {
|
||||
this.emitter.emit("room.message", roomId, raw);
|
||||
}
|
||||
|
||||
const stateKey = raw.state_key ?? "";
|
||||
|
||||
@@ -231,7 +231,7 @@ const LANGUAGE_STOP_WORDS = {
|
||||
|
||||
const CONCEPT_STOP_WORDS = new Set(
|
||||
Object.values(LANGUAGE_STOP_WORDS)
|
||||
.flatMap((words) => words)
|
||||
.flat()
|
||||
.map((word) => normalizeLowercaseStringOrEmpty(word)),
|
||||
);
|
||||
|
||||
|
||||
@@ -255,28 +255,26 @@ export async function handleNextcloudTalkInbound(params: {
|
||||
runtime.log?.(`nextcloud-talk: drop group sender ${senderId} (reason=${accessReason})`);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (access.senderAccess.decision !== "allow") {
|
||||
if (access.senderAccess.decision === "pairing") {
|
||||
await pairing.issueChallenge({
|
||||
senderId,
|
||||
senderIdLine: `Your Nextcloud user id: ${senderId}`,
|
||||
meta: { name: senderName || undefined },
|
||||
sendPairingReply: async (text) => {
|
||||
await sendMessageNextcloudTalk(roomToken, text, {
|
||||
cfg: config,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
statusSink?.({ lastOutboundAt: Date.now() });
|
||||
},
|
||||
onReplyError: (err) => {
|
||||
runtime.error?.(`nextcloud-talk: pairing reply failed for ${senderId}: ${String(err)}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
runtime.log?.(`nextcloud-talk: drop DM sender ${senderId} (reason=${accessReason})`);
|
||||
return;
|
||||
} else if (access.senderAccess.decision !== "allow") {
|
||||
if (access.senderAccess.decision === "pairing") {
|
||||
await pairing.issueChallenge({
|
||||
senderId,
|
||||
senderIdLine: `Your Nextcloud user id: ${senderId}`,
|
||||
meta: { name: senderName || undefined },
|
||||
sendPairingReply: async (text) => {
|
||||
await sendMessageNextcloudTalk(roomToken, text, {
|
||||
cfg: config,
|
||||
accountId: account.accountId,
|
||||
});
|
||||
statusSink?.({ lastOutboundAt: Date.now() });
|
||||
},
|
||||
onReplyError: (err) => {
|
||||
runtime.error?.(`nextcloud-talk: pairing reply failed for ${senderId}: ${String(err)}`);
|
||||
},
|
||||
});
|
||||
}
|
||||
runtime.log?.(`nextcloud-talk: drop DM sender ${senderId} (reason=${accessReason})`);
|
||||
return;
|
||||
}
|
||||
|
||||
if (access.commandAccess.shouldBlockControlCommand) {
|
||||
|
||||
@@ -312,13 +312,11 @@ export async function waitForFile(
|
||||
stableCount = 0;
|
||||
}
|
||||
lastSize = stat.size;
|
||||
} else {
|
||||
if (Date.now() - fileAppearedAt > emptyGiveUpMs) {
|
||||
debugError(
|
||||
`[audio-convert] waitForFile: file still empty after ${emptyGiveUpMs}ms, giving up: ${path.basename(filePath)}`,
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
} else if (Date.now() - fileAppearedAt > emptyGiveUpMs) {
|
||||
debugError(
|
||||
`[audio-convert] waitForFile: file still empty after ${emptyGiveUpMs}ms, giving up: ${path.basename(filePath)}`,
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
} catch {
|
||||
if (!fileExists && Date.now() - start > noFileGiveUpMs) {
|
||||
|
||||
@@ -107,17 +107,13 @@ function expectRpcCall(params: {
|
||||
expect(method).toBe(params.method);
|
||||
if (params.rpcParams) {
|
||||
expectFields(requireRecord(rpcParams, "rpc params"), params.rpcParams);
|
||||
} else {
|
||||
if (rpcParams === undefined) {
|
||||
throw new Error("expected rpc params argument");
|
||||
}
|
||||
} else if (rpcParams === undefined) {
|
||||
throw new Error("expected rpc params argument");
|
||||
}
|
||||
if (params.options) {
|
||||
expectFields(requireRecord(options, "rpc options"), params.options);
|
||||
} else {
|
||||
if (options === undefined) {
|
||||
throw new Error("expected rpc options argument");
|
||||
}
|
||||
} else if (options === undefined) {
|
||||
throw new Error("expected rpc options argument");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ class GroupFairQueue {
|
||||
}
|
||||
|
||||
private takeNext(): QueuedApiRequest<unknown> | undefined {
|
||||
for (let scanned = 0; scanned < this.laneOrder.length; scanned += 1) {
|
||||
for (const ignoredLaneKey of this.laneOrder) {
|
||||
this.nextLaneIndex %= this.laneOrder.length;
|
||||
const laneKey = this.laneOrder[this.nextLaneIndex];
|
||||
const queue = this.lanes.get(laneKey);
|
||||
|
||||
@@ -294,8 +294,7 @@ async function sendTelegramVoiceFallbackText(opts: {
|
||||
let firstDeliveredMessageId: number | undefined;
|
||||
const chunks = filterEmptyTelegramTextChunks(opts.chunkText(opts.text));
|
||||
let appliedReplyTo = false;
|
||||
for (let i = 0; i < chunks.length; i += 1) {
|
||||
const chunk = chunks[i];
|
||||
for (const chunk of chunks) {
|
||||
// Only apply reply reference, quote text, and buttons to the first chunk.
|
||||
const replyToForChunk = !appliedReplyTo ? opts.replyToId : undefined;
|
||||
const applyQuoteForChunk = !appliedReplyTo;
|
||||
|
||||
@@ -216,8 +216,7 @@ function shouldBypassEnvProxyForTelegramApi(env: NodeJS.ProcessEnv = process.env
|
||||
const targetHostname = normalizeLowercaseStringOrEmpty(TELEGRAM_API_HOSTNAME);
|
||||
const targetPort = 443;
|
||||
const noProxyEntries = noProxyValue.split(/[,\s]/);
|
||||
for (let i = 0; i < noProxyEntries.length; i++) {
|
||||
const entry = noProxyEntries[i];
|
||||
for (const entry of noProxyEntries) {
|
||||
if (!entry) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -149,8 +149,8 @@ export function calculateMulawRms(muLaw: Buffer): number {
|
||||
return 0;
|
||||
}
|
||||
let sum = 0;
|
||||
for (let i = 0; i < muLaw.length; i += 1) {
|
||||
const normalized = (MULAW_LINEAR_SAMPLES[muLaw[i] ?? 0] ?? 0) / PCM16_MAX_AMPLITUDE;
|
||||
for (const sample of muLaw) {
|
||||
const normalized = (MULAW_LINEAR_SAMPLES[sample] ?? 0) / PCM16_MAX_AMPLITUDE;
|
||||
sum += normalized * normalized;
|
||||
}
|
||||
return Math.sqrt(sum / muLaw.length);
|
||||
|
||||
@@ -287,14 +287,12 @@ export function createWebOnMessageHandler(params: {
|
||||
if (!gating.shouldProcess) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
} else if (!msg.sender?.e164 && !msg.senderE164 && peerId && peerId.startsWith("+")) {
|
||||
// Ensure `peerId` for DMs is stable and stored as E.164 when possible.
|
||||
if (!msg.sender?.e164 && !msg.senderE164 && peerId && peerId.startsWith("+")) {
|
||||
const normalized = normalizeE164(peerId);
|
||||
if (normalized) {
|
||||
msg.sender = { ...msg.sender, e164: normalized };
|
||||
msg.senderE164 = normalized;
|
||||
}
|
||||
const normalized = normalizeE164(peerId);
|
||||
if (normalized) {
|
||||
msg.sender = { ...msg.sender, e164: normalized };
|
||||
msg.senderE164 = normalized;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -401,9 +401,9 @@ export function findCutPoint(
|
||||
const messageTokens = estimateTokens(entry.message);
|
||||
accumulatedTokens += messageTokens;
|
||||
if (accumulatedTokens >= keepRecentTokens) {
|
||||
for (let c = 0; c < cutPoints.length; c++) {
|
||||
if (cutPoints[c] >= i) {
|
||||
cutIndex = cutPoints[c];
|
||||
for (const cutPoint of cutPoints) {
|
||||
if (cutPoint >= i) {
|
||||
cutIndex = cutPoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,7 @@ export function parseCommandArgs(argsString: string): string[] {
|
||||
let current = "";
|
||||
let inQuote: string | null = null;
|
||||
|
||||
for (let i = 0; i < argsString.length; i++) {
|
||||
const char = argsString[i];
|
||||
for (const char of argsString) {
|
||||
if (inQuote) {
|
||||
if (char === inQuote) {
|
||||
inQuote = null;
|
||||
|
||||
@@ -67,8 +67,7 @@ function walkStaticImportGraph(params) {
|
||||
const visited = new Set();
|
||||
const errors = [];
|
||||
|
||||
for (let index = 0; index < queue.length; index += 1) {
|
||||
const filePath = queue[index];
|
||||
for (const filePath of queue) {
|
||||
if (!filePath || visited.has(filePath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -101,8 +101,7 @@ function splitTopLevelArguments(source: string): string[] {
|
||||
let bracketDepth = 0;
|
||||
let braceDepth = 0;
|
||||
const quoteState: QuoteScanState = { quote: null, escaped: false };
|
||||
for (let i = 0; i < source.length; i += 1) {
|
||||
const ch = source[i];
|
||||
for (const ch of source) {
|
||||
if (quoteState.quote) {
|
||||
current += ch;
|
||||
consumeQuotedChar(quoteState, ch);
|
||||
|
||||
@@ -85,8 +85,8 @@ function descendantsOf(rootPid, stats) {
|
||||
}
|
||||
const seen = new Set([rootPid]);
|
||||
const queue = [rootPid];
|
||||
for (let index = 0; index < queue.length; index += 1) {
|
||||
for (const child of children.get(queue[index]) ?? []) {
|
||||
for (const queuedPid of queue) {
|
||||
for (const child of children.get(queuedPid) ?? []) {
|
||||
if (!seen.has(child)) {
|
||||
seen.add(child);
|
||||
queue.push(child);
|
||||
|
||||
@@ -157,8 +157,7 @@ export function expandPackageDistImportClosure(params) {
|
||||
}
|
||||
|
||||
const queue = [...expectedSet].filter((file) => fileSet.has(file));
|
||||
for (let index = 0; index < queue.length; index += 1) {
|
||||
const importerPath = queue[index];
|
||||
for (const importerPath of queue) {
|
||||
for (const importedPath of importsByImporter.get(importerPath) ?? []) {
|
||||
if (fileSet.has(importedPath) && !expectedSet.has(importedPath)) {
|
||||
expectedSet.add(importedPath);
|
||||
|
||||
@@ -391,8 +391,7 @@ function hasExplicitDisabledRunFlag(argv) {
|
||||
}
|
||||
|
||||
function hasSeparateVitestOptionValueArg(argv) {
|
||||
for (let index = 0; index < argv.length; index += 1) {
|
||||
const arg = argv[index];
|
||||
for (const arg of argv) {
|
||||
if (arg === "--") {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1338,8 +1338,7 @@ function resolveAffectedTestsFromTargetedImportScan(changedPath, cwd) {
|
||||
const seen = new Set(queue);
|
||||
const targets = [];
|
||||
|
||||
for (let index = 0; index < queue.length; index += 1) {
|
||||
const current = queue[index];
|
||||
for (const current of queue) {
|
||||
const importers = findDirectImportersWithGitGrep(cwd, current, fileSet);
|
||||
if (importers === null) {
|
||||
return null;
|
||||
@@ -1409,8 +1408,7 @@ function resolveAffectedTestsFromImportGraph(changedPath, cwd, options = {}) {
|
||||
const seen = new Set(queue);
|
||||
const targets = [];
|
||||
|
||||
for (let index = 0; index < queue.length; index += 1) {
|
||||
const current = queue[index];
|
||||
for (const current of queue) {
|
||||
for (const importer of reverseImports.get(current) ?? []) {
|
||||
if (seen.has(importer)) {
|
||||
continue;
|
||||
|
||||
@@ -422,8 +422,7 @@ function extractScriptTargetFromCommand(
|
||||
}
|
||||
};
|
||||
|
||||
for (let i = 0; i < value.length; i += 1) {
|
||||
const ch = value[i];
|
||||
for (const ch of value) {
|
||||
if (inSingle) {
|
||||
if (ch === "'") {
|
||||
inSingle = false;
|
||||
@@ -669,8 +668,7 @@ function hasUnquotedScriptHint(raw: string): boolean {
|
||||
return false;
|
||||
};
|
||||
|
||||
for (let i = 0; i < raw.length; i += 1) {
|
||||
const ch = raw[i];
|
||||
for (const ch of raw) {
|
||||
if (escaped) {
|
||||
if (!inSingle && !inDouble) {
|
||||
token += ch;
|
||||
|
||||
@@ -286,8 +286,7 @@ export async function writeCliImages(params: {
|
||||
await fs.mkdir(imageRoot, { recursive: true, mode: 0o700 });
|
||||
const store = privateFileStore(imageRoot);
|
||||
const paths: string[] = [];
|
||||
for (let i = 0; i < params.images.length; i += 1) {
|
||||
const image = params.images[i];
|
||||
for (const image of params.images) {
|
||||
const fileName = path.basename(resolveCliImagePath(image));
|
||||
const buffer = Buffer.from(image.data, "base64");
|
||||
await store.writeText(fileName, buffer);
|
||||
|
||||
@@ -2221,11 +2221,11 @@ function isJsonValue(value: unknown): value is JsonValue {
|
||||
continue;
|
||||
}
|
||||
if (Array.isArray(current.value)) {
|
||||
for (let index = 0; index < current.value.length; index += 1) {
|
||||
for (const value of current.value) {
|
||||
if (nodes + stack.length + 1 > MAX_NATIVE_HOOK_RELAY_JSON_NODES) {
|
||||
return false;
|
||||
}
|
||||
stack.push({ value: current.value[index], depth: current.depth + 1 });
|
||||
stack.push({ value, depth: current.depth + 1 });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -196,8 +196,7 @@ export function buildSubagentRunReadIndexFromRuns(params: {
|
||||
let count = 0;
|
||||
const pending = [root];
|
||||
const visited = new Set<string>([root]);
|
||||
for (let index = 0; index < pending.length; index += 1) {
|
||||
const requester = pending[index];
|
||||
for (const requester of pending) {
|
||||
if (!requester) {
|
||||
continue;
|
||||
}
|
||||
@@ -377,8 +376,7 @@ function forEachDescendantRun(
|
||||
}
|
||||
const pending = [root];
|
||||
const visited = new Set<string>([root]);
|
||||
for (let index = 0; index < pending.length; index += 1) {
|
||||
const requester = pending[index];
|
||||
for (const requester of pending) {
|
||||
if (!requester) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -30,9 +30,7 @@ export function splitShellWords(input: string | undefined, maxWords = 48): strin
|
||||
let quote: '"' | "'" | undefined;
|
||||
let escaped = false;
|
||||
|
||||
for (let i = 0; i < input.length; i += 1) {
|
||||
const char = input[i];
|
||||
|
||||
for (const char of input) {
|
||||
if (escaped) {
|
||||
current += char;
|
||||
escaped = false;
|
||||
|
||||
@@ -589,10 +589,8 @@ export function registerLogsCli(program: Command) {
|
||||
if (!emitJsonLine({ type: "log", ...parsed })) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (!emitJsonLine({ type: "raw", raw: line })) {
|
||||
return;
|
||||
}
|
||||
} else if (!emitJsonLine({ type: "raw", raw: line })) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (payload.truncated) {
|
||||
|
||||
@@ -218,8 +218,8 @@ function countJsonlLines(filePath: string): number {
|
||||
return 0;
|
||||
}
|
||||
let count = 0;
|
||||
for (let i = 0; i < raw.length; i += 1) {
|
||||
if (raw[i] === "\n") {
|
||||
for (const char of raw) {
|
||||
if (char === "\n") {
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,7 +454,7 @@ export async function getHealthSnapshot(params?: {
|
||||
boundAccounts,
|
||||
});
|
||||
const boundAccountIdsAll = Array.from(
|
||||
new Set(Array.from(channelBindings.get(plugin.id)?.values() ?? []).flatMap((ids) => ids)),
|
||||
new Set(Array.from(channelBindings.get(plugin.id)?.values() ?? []).flat()),
|
||||
);
|
||||
const accountIdsToProbe = Array.from(
|
||||
new Set(
|
||||
|
||||
@@ -86,8 +86,7 @@ function parseFlagName(arg: string): string | null {
|
||||
export function redactConfigAuditArgv(argv: readonly string[]): string[] {
|
||||
const result: string[] = [];
|
||||
let redactNext = false;
|
||||
for (let i = 0; i < argv.length; i++) {
|
||||
const current = argv[i];
|
||||
for (const current of argv) {
|
||||
if (typeof current !== "string") {
|
||||
result.push(current);
|
||||
redactNext = false;
|
||||
|
||||
@@ -91,18 +91,16 @@ function coerceSchedule(schedule: UnknownRecord) {
|
||||
|
||||
if (kind) {
|
||||
next.kind = kind;
|
||||
} else {
|
||||
if (
|
||||
typeof schedule.atMs === "number" ||
|
||||
typeof schedule.at === "string" ||
|
||||
typeof schedule.atMs === "string"
|
||||
) {
|
||||
next.kind = "at";
|
||||
} else if (everyMs !== undefined) {
|
||||
next.kind = "every";
|
||||
} else if (normalizedExpr) {
|
||||
next.kind = "cron";
|
||||
}
|
||||
} else if (
|
||||
typeof schedule.atMs === "number" ||
|
||||
typeof schedule.at === "string" ||
|
||||
typeof schedule.atMs === "string"
|
||||
) {
|
||||
next.kind = "at";
|
||||
} else if (everyMs !== undefined) {
|
||||
next.kind = "every";
|
||||
} else if (normalizedExpr) {
|
||||
next.kind = "cron";
|
||||
}
|
||||
|
||||
const parsedAtIso = parsedAtMs !== null ? timestampMsToIsoString(parsedAtMs) : undefined;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { normalizeOptionalString } from "../../packages/normalization-core/src/string-coerce.js";
|
||||
import type { FailoverReason } from "../agents/embedded-agent-helpers/types.js";
|
||||
import { resolveFailoverReasonFromError } from "../agents/failover-error.js";
|
||||
import { normalizeOptionalString } from "../../packages/normalization-core/src/string-coerce.js";
|
||||
import { normalizeCronRunDiagnostics } from "./run-diagnostics.js";
|
||||
import type { CronRunLogEntry } from "./run-log-types.js";
|
||||
import type { CronDeliveryStatus } from "./types.js";
|
||||
@@ -38,8 +38,8 @@ export function parseCronRunLogEntriesFromJsonl(
|
||||
}
|
||||
const parsed: CronRunLogEntry[] = [];
|
||||
const lines = raw.split("\n");
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
const line = lines[i]?.trim();
|
||||
for (const rawLine of lines) {
|
||||
const line = rawLine.trim();
|
||||
if (!line) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -784,8 +784,7 @@ function mirrorMessageToolVisibleReplies(messages: unknown[]): unknown[] {
|
||||
clearPending();
|
||||
};
|
||||
|
||||
for (let i = 0; i < messages.length; i++) {
|
||||
const message = messages[i];
|
||||
for (const message of messages) {
|
||||
const record = readRecord(message);
|
||||
if (!record) {
|
||||
next.push(message);
|
||||
|
||||
@@ -164,8 +164,7 @@ function estimateBase64Size(value: string | undefined): number | undefined {
|
||||
}
|
||||
let encodedLength = 0;
|
||||
let padding = 0;
|
||||
for (let index = 0; index < value.length; index += 1) {
|
||||
const char = value[index];
|
||||
for (const char of value) {
|
||||
if (!char || isBase64Whitespace(char)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -262,9 +262,7 @@ function appendDecodedText(
|
||||
sourceEndOffset: number,
|
||||
): void {
|
||||
decoded.value += value;
|
||||
for (let index = 0; index < value.length; index += 1) {
|
||||
decoded.sourceOffsets.push(sourceEndOffset);
|
||||
}
|
||||
decoded.sourceOffsets.push(...Array.from({ length: value.length }, () => sourceEndOffset));
|
||||
}
|
||||
|
||||
function identityDecodedShellText(text: string, sourceOffset = 0): DecodedShellText {
|
||||
|
||||
@@ -225,40 +225,38 @@ function splitShellPipeline(command: string): { ok: boolean; reason?: string; se
|
||||
if (line === current.delimiter) {
|
||||
pendingHeredocs.shift();
|
||||
}
|
||||
} else {
|
||||
} else if (line === current.delimiter && unquotedHeredocLogicalChunks.length === 0) {
|
||||
// An unquoted heredoc body whose previous physical line ended with
|
||||
// `\<newline>` is spliced into the next line at runtime. In that
|
||||
// case bash does not treat the next physical line as the delimiter,
|
||||
// even if it matches literally — the splice wins and the body
|
||||
// continues. Only recognize the delimiter when no continuation is
|
||||
// pending.
|
||||
if (line === current.delimiter && unquotedHeredocLogicalChunks.length === 0) {
|
||||
pendingHeredocs.shift();
|
||||
} else {
|
||||
const continued = stripUnquotedHeredocLineContinuation(line);
|
||||
unquotedHeredocLogicalChunks.push(continued.line);
|
||||
if (unquotedHeredocLogicalChunks.length > MAX_UNQUOTED_HEREDOC_CONTINUATION_LINES) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "heredoc continuation too long",
|
||||
segments: [],
|
||||
};
|
||||
}
|
||||
unquotedHeredocLogicalLength += continued.line.length;
|
||||
if (unquotedHeredocLogicalLength > MAX_UNQUOTED_HEREDOC_LOGICAL_LINE_LENGTH) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "heredoc logical line too large",
|
||||
segments: [],
|
||||
};
|
||||
}
|
||||
if (!continued.continues) {
|
||||
if (hasUnquotedHeredocExpansionToken(unquotedHeredocLogicalChunks.join(""))) {
|
||||
return { ok: false, reason: "shell expansion in unquoted heredoc", segments: [] };
|
||||
}
|
||||
unquotedHeredocLogicalChunks = [];
|
||||
unquotedHeredocLogicalLength = 0;
|
||||
pendingHeredocs.shift();
|
||||
} else {
|
||||
const continued = stripUnquotedHeredocLineContinuation(line);
|
||||
unquotedHeredocLogicalChunks.push(continued.line);
|
||||
if (unquotedHeredocLogicalChunks.length > MAX_UNQUOTED_HEREDOC_CONTINUATION_LINES) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "heredoc continuation too long",
|
||||
segments: [],
|
||||
};
|
||||
}
|
||||
unquotedHeredocLogicalLength += continued.line.length;
|
||||
if (unquotedHeredocLogicalLength > MAX_UNQUOTED_HEREDOC_LOGICAL_LINE_LENGTH) {
|
||||
return {
|
||||
ok: false,
|
||||
reason: "heredoc logical line too large",
|
||||
segments: [],
|
||||
};
|
||||
}
|
||||
if (!continued.continues) {
|
||||
if (hasUnquotedHeredocExpansionToken(unquotedHeredocLogicalChunks.join(""))) {
|
||||
return { ok: false, reason: "shell expansion in unquoted heredoc", segments: [] };
|
||||
}
|
||||
unquotedHeredocLogicalChunks = [];
|
||||
unquotedHeredocLogicalLength = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,9 +187,7 @@ export function transformMessages<TApi extends Api>(
|
||||
}
|
||||
};
|
||||
|
||||
for (let i = 0; i < transformed.length; i++) {
|
||||
const msg = transformed[i];
|
||||
|
||||
for (const msg of transformed) {
|
||||
if (msg.role === "assistant") {
|
||||
// If we have pending orphaned tool calls from a previous assistant, insert synthetic results now
|
||||
insertSyntheticToolResults();
|
||||
|
||||
@@ -19,8 +19,8 @@ const CRC_TABLE = (() => {
|
||||
/** Compute CRC32 checksum for a buffer (used in PNG chunk encoding). */
|
||||
function crc32(buf: Buffer): number {
|
||||
let crc = 0xffffffff;
|
||||
for (let i = 0; i < buf.length; i += 1) {
|
||||
crc = CRC_TABLE[(crc ^ buf[i]) & 0xff] ^ (crc >>> 8);
|
||||
for (const byte of buf) {
|
||||
crc = CRC_TABLE[(crc ^ byte) & 0xff] ^ (crc >>> 8);
|
||||
}
|
||||
return (crc ^ 0xffffffff) >>> 0;
|
||||
}
|
||||
|
||||
@@ -1277,10 +1277,8 @@ export function describeTtsAutoApplyContract() {
|
||||
expect(fetchMock).toHaveBeenCalledTimes(params.expectedFetchCalls);
|
||||
if (params.expectSamePayload) {
|
||||
expect(result).toBe(params.payload);
|
||||
} else {
|
||||
if (typeof result.mediaUrl !== "string" || result.mediaUrl.length === 0) {
|
||||
throw new Error("expected auto TTS to attach mediaUrl");
|
||||
}
|
||||
} else if (typeof result.mediaUrl !== "string" || result.mediaUrl.length === 0) {
|
||||
throw new Error("expected auto TTS to attach mediaUrl");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,5 +59,5 @@ export function getChannelEnvVars(channelId: string, params?: ChannelEnvVarLooku
|
||||
}
|
||||
|
||||
export function listKnownChannelEnvVarNames(params?: ChannelEnvVarLookupParams): string[] {
|
||||
return uniqueStrings(Object.values(resolveChannelEnvVars(params)).flatMap((keys) => keys));
|
||||
return uniqueStrings(Object.values(resolveChannelEnvVars(params)).flat());
|
||||
}
|
||||
|
||||
@@ -438,13 +438,13 @@ export function getProviderEnvVars(
|
||||
// remain available to child bridge/runtime processes.
|
||||
export function listKnownProviderAuthEnvVarNames(params?: ProviderEnvVarLookupParams): string[] {
|
||||
return uniqueStrings([
|
||||
...Object.values(resolveProviderAuthEnvVarCandidates(params)).flatMap((keys) => keys),
|
||||
...Object.values(resolveProviderEnvVars(params)).flatMap((keys) => keys),
|
||||
...Object.values(resolveProviderAuthEnvVarCandidates(params)).flat(),
|
||||
...Object.values(resolveProviderEnvVars(params)).flat(),
|
||||
]);
|
||||
}
|
||||
|
||||
export function listKnownSecretEnvVarNames(params?: ProviderEnvVarLookupParams): string[] {
|
||||
return uniqueStrings(Object.values(resolveProviderEnvVars(params)).flatMap((keys) => keys));
|
||||
return uniqueStrings(Object.values(resolveProviderEnvVars(params)).flat());
|
||||
}
|
||||
|
||||
export function omitEnvKeysCaseInsensitive(
|
||||
|
||||
@@ -291,8 +291,7 @@ function containsDiscoverableSkill(
|
||||
): boolean {
|
||||
const discoveryBudget = createSkillDiscoveryBudget(opts.maxCandidateDirs);
|
||||
const queue: Array<{ dir: string; depth: number }> = [{ dir, depth: 0 }];
|
||||
for (let index = 0; index < queue.length; index += 1) {
|
||||
const candidate = queue[index];
|
||||
for (const candidate of queue) {
|
||||
if (!candidate) {
|
||||
continue;
|
||||
}
|
||||
@@ -520,8 +519,7 @@ export function resolveNestedSkillsRoot(
|
||||
// child-directory filter as discovery so ignored folders cannot re-root.
|
||||
const discoveryBudget = createSkillDiscoveryBudget(scanLimit);
|
||||
const queue: Array<{ dir: string; depth: number }> = [{ dir: nested, depth: 0 }];
|
||||
for (let index = 0; index < queue.length; index += 1) {
|
||||
const candidate = queue[index];
|
||||
for (const candidate of queue) {
|
||||
if (!candidate) {
|
||||
continue;
|
||||
}
|
||||
@@ -999,8 +997,7 @@ function loadSkillEntries(
|
||||
}),
|
||||
);
|
||||
|
||||
for (let queueIndex = 0; queueIndex < scanQueue.length; queueIndex += 1) {
|
||||
const candidate = scanQueue[queueIndex];
|
||||
for (const candidate of scanQueue) {
|
||||
if (!candidate) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -243,7 +243,7 @@ function addTrustedSymlinkSkillWatchTargets(
|
||||
let watched = 0;
|
||||
let directoryScans = 0;
|
||||
let rawEntries = 0;
|
||||
for (let queueIndex = 0; queueIndex < queue.length; queueIndex += 1) {
|
||||
for (const queued of queue) {
|
||||
if (
|
||||
watched >= MAX_SYMLINK_WATCH_TARGETS_PER_ROOT ||
|
||||
directoryScans >= MAX_SYMLINK_WATCH_DIRECTORY_SCANS_PER_ROOT ||
|
||||
@@ -251,7 +251,7 @@ function addTrustedSymlinkSkillWatchTargets(
|
||||
) {
|
||||
break;
|
||||
}
|
||||
const current = queue[queueIndex];
|
||||
const current = queued;
|
||||
if (!current) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -350,10 +350,8 @@ export function createEventHandlers(context: EventHandlerContext) {
|
||||
if (params.wasActiveRun) {
|
||||
setActivityStatus(params.status);
|
||||
clearStreamingWatchdog();
|
||||
} else {
|
||||
if (streamingWatchdogRunId === params.runId) {
|
||||
clearStreamingWatchdog();
|
||||
}
|
||||
} else if (streamingWatchdogRunId === params.runId) {
|
||||
clearStreamingWatchdog();
|
||||
}
|
||||
void refreshSessionInfo?.();
|
||||
};
|
||||
|
||||
@@ -23,8 +23,10 @@ const ZERO_BASELINE_RULES = [
|
||||
"eslint/no-self-compare",
|
||||
"eslint/no-var",
|
||||
"eslint/no-implicit-coercion",
|
||||
"eslint/no-useless-rename",
|
||||
"eslint/no-new-wrappers",
|
||||
"eslint/no-else-return",
|
||||
"eslint/no-lonely-if",
|
||||
"eslint/no-case-declarations",
|
||||
"eslint/prefer-exponentiation-operator",
|
||||
"eslint/prefer-numeric-literals",
|
||||
@@ -43,6 +45,7 @@ const ZERO_BASELINE_RULES = [
|
||||
"typescript/no-non-null-asserted-nullish-coalescing",
|
||||
"typescript/no-unnecessary-qualifier",
|
||||
"typescript/prefer-find",
|
||||
"typescript/prefer-for-of",
|
||||
"typescript/prefer-function-type",
|
||||
"typescript/prefer-includes",
|
||||
"typescript/prefer-reduce-type-parameter",
|
||||
@@ -57,6 +60,7 @@ const ZERO_BASELINE_RULES = [
|
||||
"unicorn/no-typeof-undefined",
|
||||
"unicorn/no-useless-error-capture-stack-trace",
|
||||
"unicorn/no-zero-fractions",
|
||||
"unicorn/prefer-array-flat",
|
||||
"unicorn/prefer-array-some",
|
||||
"unicorn/prefer-dom-node-text-content",
|
||||
"unicorn/prefer-keyboard-event-key",
|
||||
|
||||
@@ -2672,17 +2672,15 @@ export function renderApp(state: AppViewState) {
|
||||
const { basePath, existing } = modelEntry;
|
||||
if (!modelId) {
|
||||
removeConfigFormValue(state, basePath);
|
||||
} else if (existing && typeof existing === "object" && !Array.isArray(existing)) {
|
||||
const fallbacks = (existing as { fallbacks?: unknown }).fallbacks;
|
||||
const next = {
|
||||
primary: modelId,
|
||||
...(Array.isArray(fallbacks) ? { fallbacks } : {}),
|
||||
};
|
||||
updateConfigFormValue(state, basePath, next);
|
||||
} else {
|
||||
if (existing && typeof existing === "object" && !Array.isArray(existing)) {
|
||||
const fallbacks = (existing as { fallbacks?: unknown }).fallbacks;
|
||||
const next = {
|
||||
primary: modelId,
|
||||
...(Array.isArray(fallbacks) ? { fallbacks } : {}),
|
||||
};
|
||||
updateConfigFormValue(state, basePath, next);
|
||||
} else {
|
||||
updateConfigFormValue(state, basePath, modelId);
|
||||
}
|
||||
updateConfigFormValue(state, basePath, modelId);
|
||||
}
|
||||
void refreshVisibleToolsEffectiveForCurrentSession(state);
|
||||
},
|
||||
|
||||
@@ -349,13 +349,11 @@ md.linkify.add("www", {
|
||||
if (c === open) {
|
||||
balance[close] = balance[close] === 0 ? 1 : 0;
|
||||
}
|
||||
} else {
|
||||
} else if (c === open) {
|
||||
// Distinct open/close (e.g., ())
|
||||
if (c === open) {
|
||||
balance[close]++;
|
||||
} else if (c === close) {
|
||||
balance[close]--;
|
||||
}
|
||||
balance[close]++;
|
||||
} else if (c === close) {
|
||||
balance[close]--;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -394,13 +392,11 @@ md.linkify.add("www", {
|
||||
len--;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
} else if (balance[ch] < 0) {
|
||||
// Distinct pair: strip if more closes than opens
|
||||
if (balance[ch] < 0) {
|
||||
balance[ch]++;
|
||||
len--;
|
||||
continue;
|
||||
}
|
||||
balance[ch]++;
|
||||
len--;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -10,8 +10,8 @@ function uuidFromBytes(bytes: Uint8Array): string {
|
||||
bytes[8] = (bytes[8] & 0x3f) | 0x80; // variant 1
|
||||
|
||||
let hex = "";
|
||||
for (let i = 0; i < bytes.length; i++) {
|
||||
hex += bytes[i].toString(16).padStart(2, "0");
|
||||
for (const byte of bytes) {
|
||||
hex += byte.toString(16).padStart(2, "0");
|
||||
}
|
||||
|
||||
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(
|
||||
|
||||
@@ -503,8 +503,7 @@ function handlePaste(e: ClipboardEvent, props: ChatProps) {
|
||||
return;
|
||||
}
|
||||
const imageItems: DataTransferItem[] = [];
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
const item = items[i];
|
||||
for (const item of items) {
|
||||
if (item.type.startsWith("image/")) {
|
||||
imageItems.push(item);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user