Merge pull request #1297 from trycua/claude/add-eslint-preserve-error-YnKYj

Add ESLint configuration and fix linting issues
This commit is contained in:
gavrielc
2026-03-21 11:57:30 +02:00
committed by GitHub
12 changed files with 1429 additions and 17 deletions

32
eslint.config.js Normal file
View File

@@ -0,0 +1,32 @@
import globals from 'globals'
import pluginJs from '@eslint/js'
import tseslint from 'typescript-eslint'
import noCatchAll from 'eslint-plugin-no-catch-all'
export default [
{ ignores: ['node_modules/', 'dist/', 'container/', 'groups/'] },
{ files: ['src/**/*.{js,ts}'] },
{ languageOptions: { globals: globals.node } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
{
plugins: { 'no-catch-all': noCatchAll },
rules: {
'preserve-caught-error': ['error', { requireCatchParameter: true }],
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
'no-catch-all/no-catch-all': 'warn',
'@typescript-eslint/no-explicit-any': 'warn',
},
},
]

1376
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,6 +15,8 @@
"prepare": "husky", "prepare": "husky",
"setup": "tsx setup/index.ts", "setup": "tsx setup/index.ts",
"auth": "tsx src/whatsapp-auth.ts", "auth": "tsx src/whatsapp-auth.ts",
"lint": "eslint src/",
"lint:fix": "eslint src/ --fix",
"test": "vitest run", "test": "vitest run",
"test:watch": "vitest" "test:watch": "vitest"
}, },
@@ -27,13 +29,18 @@
"zod": "^4.3.6" "zod": "^4.3.6"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.35.0",
"@types/better-sqlite3": "^7.6.12", "@types/better-sqlite3": "^7.6.12",
"@types/node": "^22.10.0", "@types/node": "^22.10.0",
"@vitest/coverage-v8": "^4.0.18", "@vitest/coverage-v8": "^4.0.18",
"eslint": "^9.35.0",
"eslint-plugin-no-catch-all": "^1.1.0",
"globals": "^15.12.0",
"husky": "^9.1.7", "husky": "^9.1.7",
"prettier": "^3.8.1", "prettier": "^3.8.1",
"tsx": "^4.19.0", "tsx": "^4.19.0",
"typescript": "^5.7.0", "typescript": "^5.7.0",
"typescript-eslint": "^8.35.0",
"vitest": "^4.0.18" "vitest": "^4.0.18"
}, },
"engines": { "engines": {

View File

@@ -1,4 +1,4 @@
import { describe, it, expect, beforeEach } from 'vitest'; import { describe, it, expect } from 'vitest';
import { import {
registerChannel, registerChannel,

View File

@@ -507,11 +507,7 @@ export async function runContainerAgent(
// Full input is only included at verbose level to avoid // Full input is only included at verbose level to avoid
// persisting user conversation content on every non-zero exit. // persisting user conversation content on every non-zero exit.
if (isVerbose) { if (isVerbose) {
logLines.push( logLines.push(`=== Input ===`, JSON.stringify(input, null, 2), ``);
`=== Input ===`,
JSON.stringify(input, null, 2),
``,
);
} else { } else {
logLines.push( logLines.push(
`=== Input Summary ===`, `=== Input Summary ===`,
@@ -698,7 +694,7 @@ export function writeGroupsSnapshot(
groupFolder: string, groupFolder: string,
isMain: boolean, isMain: boolean,
groups: AvailableGroup[], groups: AvailableGroup[],
registeredJids: Set<string>, _registeredJids: Set<string>,
): void { ): void {
const groupIpcDir = resolveGroupIpcPath(groupFolder); const groupIpcDir = resolveGroupIpcPath(groupFolder);
fs.mkdirSync(groupIpcDir, { recursive: true }); fs.mkdirSync(groupIpcDir, { recursive: true });

View File

@@ -96,7 +96,9 @@ export function ensureContainerRuntimeRunning(): void {
console.error( console.error(
'╚════════════════════════════════════════════════════════════════╝\n', '╚════════════════════════════════════════════════════════════════╝\n',
); );
throw new Error('Container runtime is required but failed to start'); throw new Error('Container runtime is required but failed to start', {
cause: err,
});
} }
} }

View File

@@ -40,7 +40,7 @@ describe('GroupQueue', () => {
let concurrentCount = 0; let concurrentCount = 0;
let maxConcurrent = 0; let maxConcurrent = 0;
const processMessages = vi.fn(async (groupJid: string) => { const processMessages = vi.fn(async (_groupJid: string) => {
concurrentCount++; concurrentCount++;
maxConcurrent = Math.max(maxConcurrent, concurrentCount); maxConcurrent = Math.max(maxConcurrent, concurrentCount);
// Simulate async work // Simulate async work
@@ -69,7 +69,7 @@ describe('GroupQueue', () => {
let maxActive = 0; let maxActive = 0;
const completionCallbacks: Array<() => void> = []; const completionCallbacks: Array<() => void> = [];
const processMessages = vi.fn(async (groupJid: string) => { const processMessages = vi.fn(async (_groupJid: string) => {
activeCount++; activeCount++;
maxActive = Math.max(maxActive, activeCount); maxActive = Math.max(maxActive, activeCount);
await new Promise<void>((resolve) => completionCallbacks.push(resolve)); await new Promise<void>((resolve) => completionCallbacks.push(resolve));
@@ -104,7 +104,7 @@ describe('GroupQueue', () => {
const executionOrder: string[] = []; const executionOrder: string[] = [];
let resolveFirst: () => void; let resolveFirst: () => void;
const processMessages = vi.fn(async (groupJid: string) => { const processMessages = vi.fn(async (_groupJid: string) => {
if (executionOrder.length === 0) { if (executionOrder.length === 0) {
// First call: block until we release it // First call: block until we release it
await new Promise<void>((resolve) => { await new Promise<void>((resolve) => {

View File

@@ -351,7 +351,7 @@ export class GroupQueue {
// via idle timeout or container timeout. The --rm flag cleans them up on exit. // via idle timeout or container timeout. The --rm flag cleans them up on exit.
// This prevents WhatsApp reconnection restarts from killing working agents. // This prevents WhatsApp reconnection restarts from killing working agents.
const activeContainers: string[] = []; const activeContainers: string[] = [];
for (const [jid, state] of this.groups) { for (const [_jid, state] of this.groups) {
if (state.process && !state.process.killed && state.containerName) { if (state.process && !state.process.killed && state.containerName) {
activeContainers.push(state.containerName); activeContainers.push(state.containerName);
} }

View File

@@ -33,7 +33,6 @@ import {
getAllTasks, getAllTasks,
getMessagesSince, getMessagesSince,
getNewMessages, getNewMessages,
getRegisteredGroup,
getRouterState, getRouterState,
initDatabase, initDatabase,
setRegisteredGroup, setRegisteredGroup,

View File

@@ -37,7 +37,7 @@ describe('remote-control', () => {
let readFileSyncSpy: ReturnType<typeof vi.spyOn>; let readFileSyncSpy: ReturnType<typeof vi.spyOn>;
let writeFileSyncSpy: ReturnType<typeof vi.spyOn>; let writeFileSyncSpy: ReturnType<typeof vi.spyOn>;
let unlinkSyncSpy: ReturnType<typeof vi.spyOn>; let unlinkSyncSpy: ReturnType<typeof vi.spyOn>;
let mkdirSyncSpy: ReturnType<typeof vi.spyOn>; let _mkdirSyncSpy: ReturnType<typeof vi.spyOn>;
let openSyncSpy: ReturnType<typeof vi.spyOn>; let openSyncSpy: ReturnType<typeof vi.spyOn>;
let closeSyncSpy: ReturnType<typeof vi.spyOn>; let closeSyncSpy: ReturnType<typeof vi.spyOn>;
@@ -50,7 +50,7 @@ describe('remote-control', () => {
stdoutFileContent = ''; stdoutFileContent = '';
// Default fs mocks // Default fs mocks
mkdirSyncSpy = vi _mkdirSyncSpy = vi
.spyOn(fs, 'mkdirSync') .spyOn(fs, 'mkdirSync')
.mockImplementation(() => undefined as any); .mockImplementation(() => undefined as any);
writeFileSyncSpy = vi writeFileSyncSpy = vi

View File

@@ -1,6 +1,6 @@
import { describe, it, expect, beforeEach } from 'vitest'; import { describe, it, expect, beforeEach } from 'vitest';
import { _initTestDatabase, getAllChats, storeChatMetadata } from './db.js'; import { _initTestDatabase, storeChatMetadata } from './db.js';
import { getAvailableGroups, _setRegisteredGroups } from './index.js'; import { getAvailableGroups, _setRegisteredGroups } from './index.js';
beforeEach(() => { beforeEach(() => {

View File

@@ -1,7 +1,7 @@
import fs from 'fs'; import fs from 'fs';
import os from 'os'; import os from 'os';
import path from 'path'; import path from 'path';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { afterEach, beforeEach, describe, expect, it } from 'vitest';
import { import {
isSenderAllowed, isSenderAllowed,