refactor: clean up code and improve readability across multiple files

- Removed unnecessary eslint disable comments related to intentional mutations for clarity.
- Updated import statements for consistency and organization.
- Refactored regex patterns and utility functions in various components to enhance performance and maintainability.
- Improved error handling and notifications for API errors in the teams IPC module.
- Streamlined the handling of DOM mutations in the ChatHistory and other components for better readability.
- Enhanced type definitions and added utility functions to improve code structure and type safety.
This commit is contained in:
iliya 2026-03-19 14:07:14 +02:00
parent bec8a6184a
commit 16f3fa51a3
17 changed files with 28 additions and 154 deletions

View file

@ -1,105 +0,0 @@
// electron.vite.config.ts
import { defineConfig, externalizeDepsPlugin } from "electron-vite";
import react from "@vitejs/plugin-react";
import { readFileSync } from "fs";
import { resolve } from "path";
var __electron_vite_injected_dirname = "/Users/belief/dev/projects/claude/claude_team";
var pkg = JSON.parse(readFileSync(resolve(__electron_vite_injected_dirname, "package.json"), "utf-8"));
var prodDeps = Object.keys(pkg.dependencies || {});
var bundledDeps = prodDeps.filter((d) => d !== "node-pty" && d !== "agent-teams-controller");
function nativeModuleStub() {
const STUB_ID = "\0native-stub";
return {
name: "native-module-stub",
resolveId(source) {
if (source.endsWith(".node")) return STUB_ID;
return null;
},
load(id) {
if (id === STUB_ID) return "export default {}";
return null;
}
};
}
var electron_vite_config_default = defineConfig({
main: {
plugins: [
externalizeDepsPlugin({
exclude: bundledDeps
}),
nativeModuleStub()
],
resolve: {
alias: {
"@main": resolve(__electron_vite_injected_dirname, "src/main"),
"@shared": resolve(__electron_vite_injected_dirname, "src/shared"),
"@preload": resolve(__electron_vite_injected_dirname, "src/preload")
}
},
build: {
outDir: "dist-electron/main",
rollupOptions: {
input: {
index: resolve(__electron_vite_injected_dirname, "src/main/index.ts"),
"team-fs-worker": resolve(__electron_vite_injected_dirname, "src/main/workers/team-fs-worker.ts")
},
output: {
// CJS format so bundled deps can use __dirname/require.
// Use .cjs extension since package.json has "type": "module".
format: "cjs",
entryFileNames: "[name].cjs",
// Set UV_THREADPOOL_SIZE before any module code runs.
// Must be in the banner because ESM→CJS hoists imports above top-level code.
// On Windows, fs.watch({recursive:true}) occupies a UV pool thread per watcher;
// with 3+ watchers + concurrent fs/DNS/spawn, the default 4 threads deadlock.
banner: `if(!process.env.UV_THREADPOOL_SIZE){process.env.UV_THREADPOOL_SIZE='24'}`
}
}
}
},
preload: {
plugins: [externalizeDepsPlugin()],
resolve: {
alias: {
"@preload": resolve(__electron_vite_injected_dirname, "src/preload"),
"@shared": resolve(__electron_vite_injected_dirname, "src/shared"),
"@main": resolve(__electron_vite_injected_dirname, "src/main")
}
},
build: {
outDir: "dist-electron/preload",
rollupOptions: {
input: {
index: resolve(__electron_vite_injected_dirname, "src/preload/index.ts")
},
output: {
format: "cjs",
entryFileNames: "[name].js"
}
}
}
},
renderer: {
optimizeDeps: {
include: ["@codemirror/language-data"]
},
resolve: {
alias: {
"@renderer": resolve(__electron_vite_injected_dirname, "src/renderer"),
"@shared": resolve(__electron_vite_injected_dirname, "src/shared"),
"@main": resolve(__electron_vite_injected_dirname, "src/main")
}
},
plugins: [react()],
build: {
rollupOptions: {
input: {
index: resolve(__electron_vite_injected_dirname, "src/renderer/index.html")
}
}
}
}
});
export {
electron_vite_config_default as default
};

View file

@ -63,6 +63,7 @@ import {
import { AGENT_BLOCK_CLOSE, AGENT_BLOCK_OPEN } from '@shared/constants/agentBlocks';
import { KANBAN_COLUMN_IDS } from '@shared/constants/kanban';
import { MAX_TEXT_LENGTH } from '@shared/constants/teamLimits';
import { isApiErrorMessage } from '@shared/utils/apiErrorDetector';
import {
extractFlagsFromHelp,
extractUserFlags,
@ -70,7 +71,6 @@ import {
} from '@shared/utils/cliArgsParser';
import { createLogger } from '@shared/utils/logger';
import { isRateLimitMessage } from '@shared/utils/rateLimitDetector';
import { isApiErrorMessage } from '@shared/utils/apiErrorDetector';
import crypto from 'crypto';
import { BrowserWindow, type IpcMain, type IpcMainInvokeEvent, Notification } from 'electron';
import * as fs from 'fs';
@ -235,7 +235,7 @@ function checkApiErrorMessages(
}
// Extract status code for summary
const statusMatch = msg.text.match(/^API Error:\s*(\d{3})/);
const statusMatch = /^API Error:\s*(\d{3})/.exec(msg.text);
const statusCode = statusMatch?.[1] ?? '???';
void NotificationManager.getInstance()

View file

@ -312,7 +312,6 @@ export class SubagentResolver {
* Intentionally mutates the subagent in place for consistency with other resolution methods.
*/
private enrichSubagentFromTask(subagent: Process, taskCall: ToolCall): void {
/* eslint-disable no-param-reassign -- Mutation is intentional; subagent is enriched in place */
subagent.parentTaskId = taskCall.id;
subagent.description = taskCall.taskDescription;
subagent.subagentType = taskCall.taskSubagentType;
@ -323,7 +322,6 @@ export class SubagentResolver {
if (teamName && memberName) {
subagent.team = { teamName, memberName, memberColor: '' };
}
/* eslint-enable no-param-reassign -- End of intentional mutation block */
}
/**

View file

@ -329,8 +329,8 @@ export class CliInstallerService {
loggedIn?: boolean;
authMethod?: string;
};
result.authLoggedIn = auth.loggedIn === true; // eslint-disable-line no-param-reassign -- intentional mutation of shared result object
result.authMethod = auth.authMethod ?? null; // eslint-disable-line no-param-reassign -- intentional mutation of shared result object
result.authLoggedIn = auth.loggedIn === true;
result.authMethod = auth.authMethod ?? null;
logger.info(
`Auth status: loggedIn=${result.authLoggedIn}, method=${result.authMethod ?? 'null'}` +
(authAttempt > 1 ? ` (attempt ${authAttempt})` : '')
@ -347,7 +347,7 @@ export class CliInstallerService {
logger.warn(
`Auth status check failed after ${AUTH_STATUS_MAX_RETRIES} attempts: ${getErrorMessage(err)}`
);
result.authLoggedIn = false; // eslint-disable-line no-param-reassign -- intentional mutation of shared result object
result.authLoggedIn = false;
}
}
}
@ -378,13 +378,13 @@ export class CliInstallerService {
private async fetchLatestVersion(result: CliInstallationStatus): Promise<void> {
try {
const latestRaw = await fetchText(`${GCS_BASE}/latest`);
result.latestVersion = normalizeVersion(latestRaw); // eslint-disable-line no-param-reassign -- intentional mutation of shared result object
result.latestVersion = normalizeVersion(latestRaw);
logger.info(
`Latest CLI version: "${latestRaw.trim()}" → normalized: "${result.latestVersion}"`
);
if (result.installedVersion && result.latestVersion) {
result.updateAvailable = isVersionOlder(result.installedVersion, result.latestVersion); // eslint-disable-line no-param-reassign -- intentional mutation of shared result object
result.updateAvailable = isVersionOlder(result.installedVersion, result.latestVersion);
logger.info(
`Update available: ${result.updateAvailable} (${result.installedVersion}${result.latestVersion})`
);

View file

@ -652,7 +652,6 @@ export class TeamDataService {
2000
);
if (branch && branch !== leadBranch) {
// eslint-disable-next-line no-param-reassign -- intentional in-place enrichment
member.gitBranch = branch;
}
} catch {

View file

@ -1,4 +1,3 @@
/* eslint-disable no-param-reassign -- ProvisioningRun object is intentionally mutated as a state tracker throughout the provisioning lifecycle */
import { ConfigManager } from '@main/services/infrastructure/ConfigManager';
import { NotificationManager } from '@main/services/infrastructure/NotificationManager';
import { killProcessTree, spawnCli } from '@main/utils/childProcess';
@ -7586,4 +7585,3 @@ export class TeamProvisioningService {
});
}
}
/* eslint-enable no-param-reassign -- Re-enable after TeamProvisioningService class */

View file

@ -1,9 +1,8 @@
import { AGENT_BLOCK_CLOSE, AGENT_BLOCK_OPEN } from '@shared/constants/agentBlocks';
import * as agentTeamsControllerModule from 'agent-teams-controller';
import type { AgentActionMode } from '@shared/types';
import * as agentTeamsControllerModule from 'agent-teams-controller';
const { protocols } = agentTeamsControllerModule;
const LEAD_DELEGATE_DESCRIPTION =

View file

@ -10,6 +10,7 @@ import { LocalFileSystemProvider } from '../services/infrastructure/LocalFileSys
import { type ChatHistoryEntry, isTextContent, type UserEntry } from '../types';
import type { FileSystemProvider } from '../services/infrastructure/FileSystemProvider';
import type { Readable } from 'stream';
const logger = createLogger('Util:metadataExtraction');
@ -29,6 +30,16 @@ function byteLen(chunk: string): number {
return Buffer.byteLength(chunk, 'utf8');
}
function createStreamCleanup(rl: readline.Interface, fileStream: Readable): () => void {
let cleaned = false;
return (): void => {
if (cleaned) return;
cleaned = true;
rl.close();
fileStream.destroy();
};
}
/**
* Extract CWD (current working directory) from the first entry.
* Used to get the actual project path from encoded directory names.
@ -58,17 +69,8 @@ export async function extractCwd(
let bytes = 0;
let timedOut = false;
let cleaned = false;
// Close readline FIRST so `for await` exits, then destroy the stream.
// Calling only stream.destroy() can leave readline hanging when it has
// a partial line buffered (e.g. a 400KB+ JSONL line read in 64KB chunks).
const cleanup = (): void => {
if (cleaned) return;
cleaned = true;
rl.close();
fileStream.destroy();
};
const cleanup = createStreamCleanup(rl, fileStream);
const timer = setTimeout(() => {
timedOut = true;
@ -140,14 +142,8 @@ export async function extractFirstUserMessagePreview(
let bytes = 0;
let timedOut = false;
let cleaned = false;
const cleanup = (): void => {
if (cleaned) return;
cleaned = true;
rl.close();
fileStream.destroy();
};
const cleanup = createStreamCleanup(rl, fileStream);
const timer = setTimeout(() => {
timedOut = true;

View file

@ -5,9 +5,8 @@
* to convert domain-level team payloads into the unified notification format.
*/
import { randomUUID } from 'crypto';
import { stripAgentBlocks } from '@shared/constants/agentBlocks';
import { randomUUID } from 'crypto';
import type { DetectedError } from '../services/error/ErrorMessageBuilder';
import type { TriggerColor } from '@shared/constants/triggerColors';

View file

@ -241,14 +241,13 @@ function nowMs(): number {
}
function bumpSkipReason(reasons: Record<string, number>, reason: string): void {
// eslint-disable-next-line no-param-reassign -- accumulator mutation is intentional
reasons[reason] = (reasons[reason] || 0) + 1;
}
function pushSlowest(list: SlowEntry[], entry: SlowEntry, maxLen: number): void {
list.push(entry);
list.sort((a, b) => b.ms - a.ms);
// eslint-disable-next-line no-param-reassign -- truncate in-place is intentional
if (list.length > maxLen) list.length = maxLen;
}
@ -734,10 +733,8 @@ async function readTasksDirForTeam(
}
function mergeTaskDiag(target: GetAllTasksDiag, source: TaskReadDiag): void {
// eslint-disable-next-line no-param-reassign -- accumulator mutation is intentional
target.skipped += source.skipped;
for (const [reason, count] of Object.entries(source.skipReasons)) {
// eslint-disable-next-line no-param-reassign -- accumulator mutation is intentional
target.skipReasons[reason] = (target.skipReasons[reason] || 0) + count;
}
}

View file

@ -615,20 +615,18 @@ export const ChatHistory = ({ tabId }: ChatHistoryProps): JSX.Element => {
container
.querySelectorAll<HTMLElement>('mark[data-search-result="current"]')
.forEach((prev) => {
/* eslint-disable no-param-reassign -- Directly mutating DOM element style/attributes is necessary for search result highlighting */
prev.setAttribute('data-search-result', 'match');
prev.style.backgroundColor = 'var(--highlight-bg-inactive)';
prev.style.color = 'var(--highlight-text-inactive)';
prev.style.boxShadow = '';
/* eslint-enable no-param-reassign -- Re-enable after DOM mutations */
});
}
/* eslint-disable no-param-reassign -- Directly mutating DOM element style/attributes is necessary for current search result highlighting */
el.setAttribute('data-search-result', 'current');
el.style.backgroundColor = 'var(--highlight-bg)';
el.style.color = 'var(--highlight-text)';
el.style.boxShadow = '0 0 0 1px var(--highlight-ring)';
/* eslint-enable no-param-reassign -- Re-enable after DOM mutations */
el.scrollIntoView({ behavior: 'smooth', block: 'center' });
};

View file

@ -105,10 +105,8 @@ function restoreViewport(
): void {
if (viewport.mode === 'edge') {
if (viewport.edge === 'newest') {
// eslint-disable-next-line no-param-reassign -- DOM scroll positioning requires direct mutation
container.scrollTop = order === 'newest-first' ? 0 : container.scrollHeight;
} else {
// eslint-disable-next-line no-param-reassign -- DOM scroll positioning requires direct mutation
container.scrollTop = order === 'newest-first' ? container.scrollHeight : 0;
}
return;
@ -121,7 +119,7 @@ function restoreViewport(
const containerRect = container.getBoundingClientRect();
const elRect = el.getBoundingClientRect();
const currentOffset = elRect.top - containerRect.top;
// eslint-disable-next-line no-param-reassign -- DOM scroll positioning requires direct mutation
container.scrollTop += currentOffset - viewport.offsetTop;
}

View file

@ -4,7 +4,6 @@ import { MarkdownViewer } from '@renderer/components/chat/viewers/MarkdownViewer
import { CopyButton } from '@renderer/components/common/CopyButton';
import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip';
import { CARD_ICON_MUTED, CARD_TEXT_LIGHT } from '@renderer/constants/cssVariables';
import { isApiErrorMessage } from '@shared/utils/apiErrorDetector';
import { linkifyAllMentionsInMarkdown } from '@renderer/utils/mentionLinkify';
import {
areStringArraysEqual,
@ -12,6 +11,7 @@ import {
areThoughtMessagesEquivalentForRender,
} from '@renderer/utils/messageRenderEquality';
import { linkifyTaskIdsInMarkdown, parseTaskLinkHref } from '@renderer/utils/taskReferenceUtils';
import { isApiErrorMessage } from '@shared/utils/apiErrorDetector';
import { Reply } from 'lucide-react';
import { formatTimeWithSec, ToolSummaryTooltipContent } from './LeadThoughtsGroup';

View file

@ -291,7 +291,7 @@ export const TaskCommentInput = ({
className="hidden"
onChange={(e) => {
if (e.target.files) addFiles(e.target.files);
// eslint-disable-next-line no-param-reassign -- reset file input to allow re-selecting same file
e.target.value = '';
}}
/>

View file

@ -583,7 +583,6 @@ const RootDropZone = React.forwardRef<
(el: HTMLDivElement | null) => {
setNodeRef(el);
if (typeof ref === 'function') ref(el);
// eslint-disable-next-line no-param-reassign -- combining forwarded ref with droppable ref
else if (ref) ref.current = el;
},
[ref, setNodeRef]

View file

@ -371,7 +371,6 @@ export const MentionableTextarea = React.forwardRef<HTMLTextAreaElement, Mention
if (typeof forwardedRef === 'function') {
forwardedRef(node);
} else if (forwardedRef) {
// eslint-disable-next-line no-param-reassign -- ref merging requires mutation
forwardedRef.current = node;
}
},

View file

@ -17,7 +17,6 @@ const AutoResizeTextarea = React.forwardRef<HTMLTextAreaElement, AutoResizeTexta
if (typeof forwardedRef === 'function') {
forwardedRef(node);
} else if (forwardedRef) {
// eslint-disable-next-line no-param-reassign -- ref merging requires mutation
forwardedRef.current = node;
}
},