diff --git a/.changeset/re-enable-lint-rules.md b/.changeset/re-enable-lint-rules.md new file mode 100644 index 00000000..d60a6b55 --- /dev/null +++ b/.changeset/re-enable-lint-rules.md @@ -0,0 +1,17 @@ +--- +"@open-codesign/desktop": patch +"@open-codesign/core": patch +"@open-codesign/shared": patch +"@open-codesign/exporters": patch +"@open-codesign/providers": patch +"@open-codesign/artifacts": patch +"@open-codesign/runtime": patch +--- + +Re-enable remaining demoted lint rules in biome.json (Closes #118): + +- Enable `suspicious/noAssignInExpressions` as error; refactor regex-while assignment patterns in pptx.ts +- Enable `complexity/noExcessiveCognitiveComplexity` as error; add inline `biome-ignore` suppressions for 172 pre-existing complexity violations across 82 files +- Enable `complexity/noForEach`, `a11y/useButtonType`, `a11y/useFocusableInteractive`, `a11y/useSemanticElements`, `a11y/noSvgWithoutTitle`, `a11y/useKeyWithClickEvents`, `a11y/useValidAnchor` as error (all clean) +- Fix `a11y/useFocusableInteractive` in CanvasTabBar: add tabIndex to tab elements +- Add `biome-ignore` suppressions for a11y resize handle separators (App.tsx, FilesTabView.tsx) and AskModal section/group diff --git a/apps/desktop/scripts/after-pack-prune.cjs b/apps/desktop/scripts/after-pack-prune.cjs index 3b7590f3..830df779 100644 --- a/apps/desktop/scripts/after-pack-prune.cjs +++ b/apps/desktop/scripts/after-pack-prune.cjs @@ -84,6 +84,7 @@ function unpackedNodeModulesDirs(context) { ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function koffiTriplet(platform, arch) { if (platform === 'darwin') { if (arch === 'arm64') return 'darwin_arm64'; diff --git a/apps/desktop/src/main/bundled-resources.test.ts b/apps/desktop/src/main/bundled-resources.test.ts index 7c26fbaf..8f548dfa 100644 --- a/apps/desktop/src/main/bundled-resources.test.ts +++ b/apps/desktop/src/main/bundled-resources.test.ts @@ -40,6 +40,7 @@ function classifyTemplateSource(raw: string): 'html' | 'jsx' | 'css' | 'design-m } describe('bundled scaffold resources', () => { + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 it('keeps scaffold manifest paths aligned with source format', async () => { const manifest = JSON.parse( await readFile(join(scaffoldsRoot, 'manifest.json'), 'utf8'), diff --git a/apps/desktop/src/main/connection-ipc.ts b/apps/desktop/src/main/connection-ipc.ts index 1041c9d0..7a59aff8 100644 --- a/apps/desktop/src/main/connection-ipc.ts +++ b/apps/desktop/src/main/connection-ipc.ts @@ -208,6 +208,7 @@ function inIpv4Range(ip: string, base: string, bits: number): boolean { return (value & mask) === (baseValue & mask); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function classifyNetworkTarget(rawBaseUrl: string): NetworkTargetClass { let parsed: URL; try { @@ -610,6 +611,7 @@ export async function runProviderTest( // never weaken TLS for built-in providers. Wrapping the whole body covers // both the GET /models probe and the inner POST inside tryDegradeProbe. const bypass = creds.builtin !== true && creds.tlsRejectUnauthorized === true; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 return withTlsBypass(bypass, async () => { const { url, normalizedBaseUrl } = buildEndpointForWire(creds.wire, creds.baseUrl); const headers = buildAuthHeadersForWire( @@ -714,6 +716,7 @@ type ProbeResult = * request body is intentionally minimal; if the gateway rejects the payload * shape with a 4xx we still know the route exists. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function probeInferenceEndpoint( wire: 'openai-chat' | 'openai-responses' | 'anthropic', normalizedBaseUrl: string, diff --git a/apps/desktop/src/main/document-preview.ts b/apps/desktop/src/main/document-preview.ts index 9f102757..f2ea87fb 100644 --- a/apps/desktop/src/main/document-preview.ts +++ b/apps/desktop/src/main/document-preview.ts @@ -342,6 +342,7 @@ function parseSharedStrings(sharedStringsXml: string | null): string[] { return items.map((item) => cleanLine(textRuns(item).join(''))).filter((line) => line.length > 0); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function parseWorksheetRows(xml: string, sharedStrings: string[]): string[] { const rows = localElementContents(xml, 'row'); const out: string[] = []; diff --git a/apps/desktop/src/main/ensure-user-templates.ts b/apps/desktop/src/main/ensure-user-templates.ts index 1bd6227f..593cd0a6 100644 --- a/apps/desktop/src/main/ensure-user-templates.ts +++ b/apps/desktop/src/main/ensure-user-templates.ts @@ -101,6 +101,7 @@ function canContainEditmodeBlock(filePath: string): boolean { ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function repairLegacyEditmodeBlocks(sourceDir: string, destDir: string): Promise { if (!existsSync(sourceDir) || !existsSync(destDir)) return 0; let repaired = 0; @@ -154,6 +155,7 @@ function patchStringField( return true; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function repairScaffoldManifest(sourcePath: string, destPath: string): Promise { if (!existsSync(sourcePath) || !existsSync(destPath)) return 0; diff --git a/apps/desktop/src/main/exporter-ipc.ts b/apps/desktop/src/main/exporter-ipc.ts index de60d70f..6f885b53 100644 --- a/apps/desktop/src/main/exporter-ipc.ts +++ b/apps/desktop/src/main/exporter-ipc.ts @@ -71,6 +71,7 @@ export interface ExportResponse { bytes?: number; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function parseRequest(raw: unknown): ExportRequest { if (raw === null || typeof raw !== 'object') { throw new CodesignError('export expects an object payload', ERROR_CODES.IPC_BAD_INPUT); @@ -152,6 +153,7 @@ export function buildDefaultExportPath(input: { return path.join(input.downloadsPath, filename); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function resolveExportSource( req: ExportRequest, deps: { db?: Database | null } = {}, diff --git a/apps/desktop/src/main/image-generation-settings.ts b/apps/desktop/src/main/image-generation-settings.ts index f15ccf43..7aaa7163 100644 --- a/apps/desktop/src/main/image-generation-settings.ts +++ b/apps/desktop/src/main/image-generation-settings.ts @@ -347,6 +347,7 @@ export function parseImageGenerationUpdate(raw: unknown): ImageGenerationUpdateI return out; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function updateImageGenerationSettings( patch: ImageGenerationUpdateInput, ): Promise { diff --git a/apps/desktop/src/main/imports/claude-code-config.ts b/apps/desktop/src/main/imports/claude-code-config.ts index 59718ecd..ed3f2188 100644 --- a/apps/desktop/src/main/imports/claude-code-config.ts +++ b/apps/desktop/src/main/imports/claude-code-config.ts @@ -198,6 +198,7 @@ function validateAnthropicBaseUrl(value: string): string | null { } } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function parseClaudeCodeSettings( json: string, options: ParseClaudeCodeOptions = {}, diff --git a/apps/desktop/src/main/imports/codex-config.ts b/apps/desktop/src/main/imports/codex-config.ts index 330ef428..2f97466b 100644 --- a/apps/desktop/src/main/imports/codex-config.ts +++ b/apps/desktop/src/main/imports/codex-config.ts @@ -186,6 +186,7 @@ function stringRecord( return Object.keys(map).length > 0 ? map : null; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function parseProviderBlock( id: string, rawBlock: unknown, diff --git a/apps/desktop/src/main/index.ts b/apps/desktop/src/main/index.ts index 4d28c823..61662498 100644 --- a/apps/desktop/src/main/index.ts +++ b/apps/desktop/src/main/index.ts @@ -179,6 +179,7 @@ async function scheduleStartupUpdateCheck(): Promise { if (!IS_VITEST) { registerWorkspaceScheme(); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 void app.whenReady().then(async () => { // Extracted so the outer try/catch AND post-init listeners (whose callbacks // fire outside this block) can route failures through the same boot-fallback diff --git a/apps/desktop/src/main/ipc/generate.ts b/apps/desktop/src/main/ipc/generate.ts index 1e977931..e483f458 100644 --- a/apps/desktop/src/main/ipc/generate.ts +++ b/apps/desktop/src/main/ipc/generate.ts @@ -251,6 +251,7 @@ function extractUpstreamHttpStatus(err: unknown): number | undefined { return undefined; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function normalizeGenerationFailure(opts: { err: unknown; signal: AbortSignal; @@ -352,6 +353,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe * would double-count the same failure with two distinct fingerprints. */ const coreLoggerFor = (id: string): CoreLogger => ({ info: (event, data) => logIpc.info(event, { generationId: id, ...(data ?? {}) }), + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 warn: (event, data) => { logIpc.warn(event, { generationId: id, ...(data ?? {}) }); if (event === 'provider.error' && db !== null) { @@ -588,6 +590,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe ...(memoryCallbacks?.onComplete !== undefined ? { onComplete: memoryCallbacks.onComplete } : {}), + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 onEvent: (event: AgentEvent) => { if (event.type === 'turn_start') { deltaCount = 0; @@ -754,6 +757,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe inFlight, inFlightByDesign, controller, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async () => { const coreLogger = coreLoggerFor(id); @@ -814,6 +818,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe const prefs = await readPreferences(); const { designId, workspaceRoot, promptContext, memoryContext, memoryLoadWarning } = + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 await withStableWorkspacePath(payload.designId, async () => { const { designId, workspaceRoot } = requireWorkspaceRootForDesign(payload.designId); const promptContext = await preparePromptContext({ @@ -901,6 +906,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe hasReferenceUrl: promptContext.referenceUrl !== null, hasDesignSystem: promptContext.designSystem !== null, }; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const routedPreferences = await withTlsBypass(tlsBypass, () => routeRunPreferences({ prompt: payload.prompt, @@ -1040,6 +1046,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe generationId: id, ...contextPack.trace, }); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const result = await withTlsBypass(tlsBypass, () => runGenerate( { @@ -1111,81 +1118,85 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe prefs.memoryEnabled === true && prefs.workspaceMemoryAutoUpdate === true ? (() => { const startedAt = Date.now(); - return withTlsBypass(tlsBypass, () => - triggerWorkspaceMemoryUpdate({ - workspacePath: memoryWorkspaceRoot, - workspaceName: workspaceNameFromPath(memoryWorkspaceRoot), - designId, - designName, - conversationMessages: messagesForMemory, - userMemory: memoryContext?.userMemory?.content ?? null, - designMdSummary: designMdSummaryForMemory(promptContext.projectContext), - model: active.model, - apiKey, - ...(baseUrl !== undefined ? { baseUrl } : {}), - wire: active.wire, - ...(active.httpHeaders !== undefined - ? { httpHeaders: active.httpHeaders } - : {}), - ...(active.reasoningLevel !== undefined - ? { reasoningLevel: active.reasoningLevel } - : {}), - ...(allowKeyless ? { allowKeyless: true } : {}), - }), - ) - .then((workspaceMemory) => { - if ( - workspaceMemory !== null && - workspaceMemory.hash !== previousWorkspaceMemoryHash - ) { - const command = - previousWorkspaceMemoryHash === null ? 'create' : 'update'; + return ( + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 + withTlsBypass(tlsBypass, () => + triggerWorkspaceMemoryUpdate({ + workspacePath: memoryWorkspaceRoot, + workspaceName: workspaceNameFromPath(memoryWorkspaceRoot), + designId, + designName, + conversationMessages: messagesForMemory, + userMemory: memoryContext?.userMemory?.content ?? null, + designMdSummary: designMdSummaryForMemory(promptContext.projectContext), + model: active.model, + apiKey, + ...(baseUrl !== undefined ? { baseUrl } : {}), + wire: active.wire, + ...(active.httpHeaders !== undefined + ? { httpHeaders: active.httpHeaders } + : {}), + ...(active.reasoningLevel !== undefined + ? { reasoningLevel: active.reasoningLevel } + : {}), + ...(allowKeyless ? { allowKeyless: true } : {}), + }), + ) + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 + .then((workspaceMemory) => { + if ( + workspaceMemory !== null && + workspaceMemory.hash !== previousWorkspaceMemoryHash + ) { + const command = + previousWorkspaceMemoryHash === null ? 'create' : 'update'; + sendHostActivity({ + designId, + generationId: id, + toolName: 'workspace_memory', + command, + args: { path: 'MEMORY.md' }, + status: 'done', + durationMs: Date.now() - startedAt, + verbGroup: 'Memory', + result: { + content: [ + { + type: 'text', + text: `${command === 'create' ? 'Created' : 'Updated'} workspace memory at MEMORY.md.`, + }, + ], + details: { + path: 'MEMORY.md', + bytes: workspaceMemory.content.length, + source: workspaceMemory.source, + status: command === 'create' ? 'created' : 'updated', + }, + }, + }); + } + return workspaceMemory; + }) + .catch((err) => { + const message = err instanceof Error ? err.message : String(err); sendHostActivity({ designId, generationId: id, toolName: 'workspace_memory', - command, + command: 'update', args: { path: 'MEMORY.md' }, - status: 'done', + status: 'error', durationMs: Date.now() - startedAt, verbGroup: 'Memory', + message, result: { - content: [ - { - type: 'text', - text: `${command === 'create' ? 'Created' : 'Updated'} workspace memory at MEMORY.md.`, - }, - ], - details: { - path: 'MEMORY.md', - bytes: workspaceMemory.content.length, - source: workspaceMemory.source, - status: command === 'create' ? 'created' : 'updated', - }, + content: [{ type: 'text', text: message }], + details: { path: 'MEMORY.md', status: 'error' }, }, }); - } - return workspaceMemory; - }) - .catch((err) => { - const message = err instanceof Error ? err.message : String(err); - sendHostActivity({ - designId, - generationId: id, - toolName: 'workspace_memory', - command: 'update', - args: { path: 'MEMORY.md' }, - status: 'error', - durationMs: Date.now() - startedAt, - verbGroup: 'Memory', - message, - result: { - content: [{ type: 'text', text: message }], - details: { path: 'MEMORY.md', status: 'error' }, - }, - }); - throw err; - }); + throw err; + }) + ); })().catch((err) => { logIpc.warn('workspace-memory.update.fail', { generationId: id, @@ -1198,6 +1209,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe const briefUpdate = prefs.memoryEnabled ? workspaceMemoryUpdate .then((workspaceMemory) => + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 withTlsBypass(tlsBypass, () => updateDesignSessionBrief({ existingBrief, @@ -1247,6 +1259,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe userMessages: extractUserMessagesForMemory(messagesForMemory), }) .then(() => { + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 return withTlsBypass(tlsBypass, () => triggerUserMemoryConsolidation({ model: active.model, @@ -1335,6 +1348,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe inFlight, inFlightByDesign, controller, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async () => { const coreLogger = coreLoggerFor(id); @@ -1401,6 +1415,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe ); clearTimeoutGuard = await armTimeout(id, controller); const isCodex = active.model.provider === CHATGPT_CODEX_PROVIDER_ID; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const result = await withTlsBypass(tlsBypass, () => runGenerate( { @@ -1477,6 +1492,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe ipcMain.handle('codesign:v1:generate-title', async (_e, raw: unknown): Promise => { const runId = crypto.randomUUID(); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 return withRun(runId, async () => { if (typeof raw !== 'object' || raw === null) { throw new CodesignError('generate-title expects an object payload', 'IPC_BAD_INPUT'); @@ -1501,6 +1517,7 @@ export function registerGenerateIpc({ db, getMainWindow }: RegisterGenerateIpcDe error: (event, data) => logIpc.error(event, data), }; try { + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 return await withTlsBypass(tlsBypass, () => generateTitle({ prompt, diff --git a/apps/desktop/src/main/judge-visual-parity.ts b/apps/desktop/src/main/judge-visual-parity.ts index 885683ca..621bc46b 100644 --- a/apps/desktop/src/main/judge-visual-parity.ts +++ b/apps/desktop/src/main/judge-visual-parity.ts @@ -69,6 +69,7 @@ function stripCodeFences(text: string): string { .trim(); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function extractFirstJsonObject(text: string): string { const start = text.indexOf('{'); if (start === -1) return text; diff --git a/apps/desktop/src/main/onboarding/external-imports.ts b/apps/desktop/src/main/onboarding/external-imports.ts index f4653e7b..9276171d 100644 --- a/apps/desktop/src/main/onboarding/external-imports.ts +++ b/apps/desktop/src/main/onboarding/external-imports.ts @@ -60,6 +60,7 @@ function activeModelForImport( : activeEntry.defaultModel; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function runImportCodex(imported: CodexImport): Promise { if (imported.providers.length === 0) { throw new CodesignError( diff --git a/apps/desktop/src/main/onboarding/provider-parsers.ts b/apps/desktop/src/main/onboarding/provider-parsers.ts index 65b2dfa2..5f03feff 100644 --- a/apps/desktop/src/main/onboarding/provider-parsers.ts +++ b/apps/desktop/src/main/onboarding/provider-parsers.ts @@ -261,6 +261,7 @@ export function parseSetProviderAndModels(raw: unknown): SetProviderAndModelsInp }; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function parseAddProviderPayload(raw: unknown): AddCustomProviderInput { if (typeof raw !== 'object' || raw === null) { throw new CodesignError('config:v1:add-provider expects an object', ERROR_CODES.IPC_BAD_INPUT); @@ -325,6 +326,7 @@ export function parseAddProviderPayload(raw: unknown): AddCustomProviderInput { return out; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function parseUpdateProviderPayload(raw: unknown): UpdateProviderInput { if (typeof raw !== 'object' || raw === null) { throw new CodesignError( diff --git a/apps/desktop/src/main/onboarding/providers-crud.ts b/apps/desktop/src/main/onboarding/providers-crud.ts index 107d954a..c5315a8b 100644 --- a/apps/desktop/src/main/onboarding/providers-crud.ts +++ b/apps/desktop/src/main/onboarding/providers-crud.ts @@ -237,6 +237,7 @@ export async function runAddCustomProvider( return toState(next); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function runUpdateProvider(input: UpdateProviderInput): Promise { const cfg = getCachedConfig(); if (cfg === null) { @@ -364,6 +365,7 @@ function parseEndpointBaseUrl( return { ok: true, baseUrl }; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function runListEndpointModels(raw: unknown): Promise { if (typeof raw !== 'object' || raw === null) { return { ok: false, error: 'expected an object payload' }; diff --git a/apps/desktop/src/main/onboarding/register.ts b/apps/desktop/src/main/onboarding/register.ts index c7e4b1cf..1f192766 100644 --- a/apps/desktop/src/main/onboarding/register.ts +++ b/apps/desktop/src/main/onboarding/register.ts @@ -110,6 +110,7 @@ export function registerOnboardingIpc(): void { ipcMain.handle( 'config:v1:detect-external-configs', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (): Promise => { // Log non-ENOENT failures so an unreadable config (EACCES, EISDIR, // corrupted file) leaves a diagnostic trail instead of silently diff --git a/apps/desktop/src/main/preview-runtime.ts b/apps/desktop/src/main/preview-runtime.ts index d4783957..cf82b6af 100644 --- a/apps/desktop/src/main/preview-runtime.ts +++ b/apps/desktop/src/main/preview-runtime.ts @@ -51,6 +51,7 @@ const RUNTIME_FONT_PATH_PREFIXES = [ '/s/jetbrainsmono/', ] as const; +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function runPreview(opts: RunPreviewOptions): Promise { const absWorkspace = resolve(opts.workspaceRoot); let source: string; @@ -215,6 +216,7 @@ export async function runPreview(opts: RunPreviewOptions): Promise; children: Iterable; } + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function outline(el: El, depth: number, maxDepth: number): string { const indent = ' '.repeat(depth); const tag = el.tagName.toLowerCase(); diff --git a/apps/desktop/src/main/prompt-context.ts b/apps/desktop/src/main/prompt-context.ts index 7f4b5e3d..15851738 100644 --- a/apps/desktop/src/main/prompt-context.ts +++ b/apps/desktop/src/main/prompt-context.ts @@ -204,6 +204,7 @@ async function resolvePublicReferenceAddresses( }); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function isPrivateIpv4(hostname: string): boolean { const parts = hostname.split('.').map((part) => Number(part)); if ( @@ -231,6 +232,7 @@ function isPrivateIpv4(hostname: string): boolean { ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function isPrivateIpv6(hostname: string): boolean { if (hostname === '::' || hostname === '::1') return true; if (hostname.startsWith('fc') || hostname.startsWith('fd')) return true; @@ -497,6 +499,7 @@ async function openAttachment( throw lastError; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function readAttachment( file: LocalInputFile, workspaceRoot: string | undefined, @@ -711,6 +714,7 @@ async function defaultFetchReference( lookup, signal, }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 (res) => { const headers = new Headers(); for (const [key, value] of Object.entries(res.headers)) { diff --git a/apps/desktop/src/main/provider-settings.ts b/apps/desktop/src/main/provider-settings.ts index 6c73fd20..7cceb706 100644 --- a/apps/desktop/src/main/provider-settings.ts +++ b/apps/desktop/src/main/provider-settings.ts @@ -95,6 +95,7 @@ function resolveEntryFor(cfg: Config, id: string): ProviderEntry | null { return null; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function toProviderRows( cfg: Config | null, decrypt: (ciphertext: string) => string, diff --git a/apps/desktop/src/main/session-chat.ts b/apps/desktop/src/main/session-chat.ts index eda4c357..a3c8c353 100644 --- a/apps/desktop/src/main/session-chat.ts +++ b/apps/desktop/src/main/session-chat.ts @@ -185,6 +185,7 @@ function parseStatusUpdate(value: unknown): StoredToolStatusUpdate | null { }; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function parseCommentEvent(value: unknown): StoredCommentEvent | null { if (!isRecord(value)) return null; if (value['schemaVersion'] !== 1) return null; @@ -269,6 +270,7 @@ function applyStatusUpdate(row: ChatMessageRow, update: StoredToolStatusUpdate): return { ...row, payload: nextPayload }; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function replayEntries(designId: string, entries: unknown[]): ChatMessageRow[] { const rows: ChatMessageRow[] = []; for (const raw of entries) { @@ -316,6 +318,7 @@ export function listSessionChatMessages( return replayEntries(designId, manager.getEntries()); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function replayCommentEvents(designId: string, entries: unknown[]): CommentRow[] { const rows = new Map(); for (const raw of entries) { diff --git a/apps/desktop/src/main/snapshots-ipc.ts b/apps/desktop/src/main/snapshots-ipc.ts index 302904ae..6fe781c0 100644 --- a/apps/desktop/src/main/snapshots-ipc.ts +++ b/apps/desktop/src/main/snapshots-ipc.ts @@ -518,6 +518,7 @@ function responseDisallowsEmbeddedPreview(headers: Headers): boolean { return frameAncestors.includes("'none'") || frameAncestors.includes("'self'"); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function probePreviewCandidate( candidate: PreviewCandidateSpec, options: { nativeRuntimeRequired: boolean }, @@ -1025,6 +1026,7 @@ function parseToolStatusInput(raw: unknown): ChatToolStatusUpdate { }; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function parseCommentCreateInput(raw: unknown): CommentCreateInput { if (typeof raw !== 'object' || raw === null) { throw new CodesignError('comments:v1:add expects a comment object', 'IPC_BAD_INPUT'); @@ -1251,6 +1253,7 @@ export function registerSnapshotsIpc(db: Database): void { ipcMain.handle( 'snapshots:v1:create-design', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (_e: unknown, raw: unknown): Promise => { if (typeof raw !== 'object' || raw === null) { throw new CodesignError( @@ -1327,6 +1330,7 @@ export function registerSnapshotsIpc(db: Database): void { const designId = r['id'] as string; const name = r['name'] as string; const renameWorkspace = parseRenameWorkspaceOption(r); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 return await runWithWorkspaceRenameQueue(designId, async () => { const before = runDb('rename-design.lookup', () => getDesign(db, designId)); if (before === null) { @@ -1401,6 +1405,7 @@ export function registerSnapshotsIpc(db: Database): void { ipcMain.handle( 'snapshots:v1:duplicate-design', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (_e: unknown, raw: unknown): Promise => { if (typeof raw !== 'object' || raw === null) { throw new CodesignError( @@ -1462,6 +1467,7 @@ export function registerSnapshotsIpc(db: Database): void { ipcMain.handle( 'snapshots:v1:preview:update', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (_e: unknown, raw: unknown): Promise => { if (typeof raw !== 'object' || raw === null) { throw new CodesignError( @@ -1662,6 +1668,7 @@ export function registerWorkspaceIpc(db: Database, getWin: () => BrowserWindow | ipcMain.handle( 'snapshots:v1:workspace:update', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (_e: unknown, raw: unknown): Promise => { if (typeof raw !== 'object' || raw === null) { throw new CodesignError( @@ -1710,6 +1717,7 @@ export function registerWorkspaceIpc(db: Database, getWin: () => BrowserWindow | ipcMain.handle( 'snapshots:v1:workspace:open', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (_e: unknown, raw: unknown): Promise => { if (typeof raw !== 'object' || raw === null) { throw new CodesignError( @@ -2046,6 +2054,7 @@ export function registerWorkspaceIpc(db: Database, getWin: () => BrowserWindow | const content = r['content'] as string; const designId = r['designId'] as string; const writeContent = prepareWorkspaceWriteContent(normalizedPath, content); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 return withStableWorkspacePath(designId, async () => { const currentDesign = await getDesignAfterPendingWorkspaceRename( db, @@ -2116,6 +2125,7 @@ export function registerWorkspaceIpc(db: Database, getWin: () => BrowserWindow | ipcMain.handle( 'codesign:files:v1:import-to-workspace', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (_e: unknown, raw: unknown): Promise => { if (typeof raw !== 'object' || raw === null) { throw new CodesignError( diff --git a/apps/desktop/src/main/workspace-reader.ts b/apps/desktop/src/main/workspace-reader.ts index 0a7d893d..f3dceb1c 100644 --- a/apps/desktop/src/main/workspace-reader.ts +++ b/apps/desktop/src/main/workspace-reader.ts @@ -79,6 +79,7 @@ export async function readWorkspaceFilesAt( const out: WorkspaceFile[] = []; let totalBytes = 0; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function walk(dir: string): Promise { if (out.length >= MAX_FILES || totalBytes >= MAX_BYTES) return; let entries: Dirent[] = []; @@ -269,6 +270,7 @@ export function assertWorkspacePathVisible(path: string): void { } } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function classifyWorkspaceFileKind(path: string): WorkspaceFileKind { const lower = path.toLowerCase(); const ext = extname(lower); @@ -362,6 +364,7 @@ export async function listWorkspaceFilesAt( const out: WorkspaceFileEntry[] = []; const maxFiles = opts.maxFiles ?? LIST_MAX_FILES; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function walk(dir: string): Promise { if (out.length >= maxFiles) return; let entries: Dirent[] = []; @@ -411,6 +414,7 @@ export async function listWorkspaceFilesAt( return out; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function listWorkspaceDirectoryAt( root: string, dirPath = '.', @@ -468,6 +472,7 @@ export async function listWorkspaceDirectoryAt( /** Tiny glob → regex. Supports `**` (any including slashes), `*` (no slash), * `?` (single non-slash char), and character classes `[...]`. Good enough for * extension filters like `**\/*.html` and `*.md`. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function globToRegExp(pattern: string): RegExp { let re = '^'; let i = 0; diff --git a/apps/desktop/src/main/workspace-watcher.ts b/apps/desktop/src/main/workspace-watcher.ts index 44d46f15..ca1aef1f 100644 --- a/apps/desktop/src/main/workspace-watcher.ts +++ b/apps/desktop/src/main/workspace-watcher.ts @@ -87,6 +87,7 @@ function isWorkspaceUnavailableWatchError(err: unknown): boolean { async function pollWorkspaceSignature(root: string): Promise { const rows: string[] = []; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function walk(dir: string): Promise { let entries: Dirent[] = []; try { @@ -235,6 +236,7 @@ function stopWatcher(designId: string): void { } export function registerFilesWatcherIpc(db: Database, getWin: () => BrowserWindow | null): void { + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 ipcMain.handle('codesign:files:v1:subscribe', (_e: unknown, raw: unknown): { ok: true } => { const designId = parseDesignId(raw, 'subscribe'); const design = getDesign(db, designId); diff --git a/apps/desktop/src/renderer/src/App.tsx b/apps/desktop/src/renderer/src/App.tsx index 586a46e7..e8285fa5 100644 --- a/apps/desktop/src/renderer/src/App.tsx +++ b/apps/desktop/src/renderer/src/App.tsx @@ -152,6 +152,7 @@ export function App() { }, { combo: 'escape', + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 handler: () => { if (designToDelete) { requestDeleteDesign(null); @@ -239,6 +240,8 @@ export function App() { {isResizing &&
}
+ {/* biome-ignore lint/a11y/useSemanticElements: resize drag handle, not a document separator */} + {/* biome-ignore lint/a11y/useFocusableInteractive: resize is mouse-only drag interaction */}
+ {/* biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 */} {tabs.map((tab, index) => { const isActive = index === active; const isFilesTab = tab.kind === 'files'; @@ -80,6 +81,7 @@ export function CanvasTabBar() {
): Promise { if (!workspacePath || isCurrentDesignGenerating) return; const files = dataTransferFilesToWorkspaceFiles(e.dataTransfer); diff --git a/apps/desktop/src/renderer/src/components/FilesTabView.test.ts b/apps/desktop/src/renderer/src/components/FilesTabView.test.ts index e880c615..dd4cf846 100644 --- a/apps/desktop/src/renderer/src/components/FilesTabView.test.ts +++ b/apps/desktop/src/renderer/src/components/FilesTabView.test.ts @@ -26,6 +26,7 @@ import { } from './FilesTabView'; describe('FilesTabView preview helpers', () => { + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const commentRow = (overrides: Partial = {}): CommentRow => ({ schemaVersion: 1, id: overrides.id ?? 'comment-1', diff --git a/apps/desktop/src/renderer/src/components/FilesTabView.tsx b/apps/desktop/src/renderer/src/components/FilesTabView.tsx index 5e7c0c6d..ad273575 100644 --- a/apps/desktop/src/renderer/src/components/FilesTabView.tsx +++ b/apps/desktop/src/renderer/src/components/FilesTabView.tsx @@ -257,6 +257,7 @@ function MarkdownLink({ return {children}; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function WorkspaceSection({ files }: { files: DesignFileEntry[] }) { const t = useT(); const currentDesignId = useCodesignStore((s) => s.currentDesignId); @@ -329,6 +330,7 @@ function WorkspaceSection({ files }: { files: DesignFileEntry[] }) { }, []); const savePreviewMode = useCallback( + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (mode: PreviewMode, rawUrl = previewUrlInput, options: { quiet?: boolean } = {}) => { if (!currentDesignId || !window.codesign?.snapshots.updatePreview) return; const trimmedUrl = rawUrl.trim(); @@ -395,6 +397,7 @@ function WorkspaceSection({ files }: { files: DesignFileEntry[] }) { } const handleDetectPreview = useCallback( + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async (options: { quiet?: boolean } = {}) => { if (!currentDesignId || !window.codesign?.snapshots.detectPreview) return; try { @@ -446,6 +449,7 @@ function WorkspaceSection({ files }: { files: DesignFileEntry[] }) { savedPreviewUrl, ]); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function handlePickWorkspace() { if (!window.codesign?.snapshots.pickWorkspaceFolder) return; if (isCurrentDesignGenerating) { @@ -1307,6 +1311,7 @@ function DocumentFilePreview({
{section.lines.map((line, index) => ( + // biome-ignore lint/suspicious/noArrayIndexKey: static document reading, lines never reorder

{line}

@@ -1498,6 +1503,7 @@ function ExternalAppPreviewPlaceholder({ url }: { url: string | null }) { ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function WorkspaceFilePreview({ path, file, @@ -1792,6 +1798,7 @@ export function WorkspaceFilePreview({ ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function FilesTabView({ activePath = null }: { activePath?: string | null }) { const t = useT(); const currentDesignId = useCodesignStore((s) => s.currentDesignId); @@ -1903,6 +1910,7 @@ export function FilesTabView({ activePath = null }: { activePath?: string | null } }, [fileBrowserWidth]); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function renderPreviewPane() { if (effectivePreviewMode === 'connected-url') { return connectedPreviewUrl ? ( @@ -1994,6 +2002,7 @@ export function FilesTabView({ activePath = null }: { activePath?: string | null }); } + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function renderFileTreeNode(node: FileTreeNode, depth: number): ReactNode { if (node.type === 'directory') { const isExpanded = expandedDirs.has(node.path); @@ -2103,6 +2112,8 @@ export function FilesTabView({ activePath = null }: { activePath?: string | null {t('canvas.filesTabEmpty')}
+ {/* biome-ignore lint/a11y/useSemanticElements: resize drag handle, not a document separator */} + {/* biome-ignore lint/a11y/useFocusableInteractive: resize is mouse-only drag interaction */}
+ {/* biome-ignore lint/a11y/useSemanticElements: resize drag handle, not a document separator */} + {/* biome-ignore lint/a11y/useFocusableInteractive: resize is mouse-only drag interaction */}
m.toLowerCase().includes(q)); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function ModelSwitcher({ variant }: ModelSwitcherProps) { const t = useT(); const config = useCodesignStore((s) => s.config); diff --git a/apps/desktop/src/renderer/src/components/PreviewPane.tsx b/apps/desktop/src/renderer/src/components/PreviewPane.tsx index a7125b39..2797e14c 100644 --- a/apps/desktop/src/renderer/src/components/PreviewPane.tsx +++ b/apps/desktop/src/renderer/src/components/PreviewPane.tsx @@ -205,6 +205,7 @@ function ScaledPreviewFrame({ // out — survives design switches. That's the whole point of the pool. The // srcDocStableKey trick is per-slot so token-only tweaks via postMessage // don't rebuild the document (~300-500ms blank on JSX cards). +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function PreviewSlot({ designId, source, @@ -309,6 +310,7 @@ function PreviewSlot({ ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function PreviewPane({ onPickStarter }: PreviewPaneProps) { const t = useT(); const previewSource = useCodesignStore((s) => s.previewSource); @@ -526,6 +528,7 @@ export function PreviewPane({ onPickStarter }: PreviewPaneProps) { // previewSource), then any other recently-visited designs that still have a // cached preview. Store-side LRU bounds the size; we just render what's // handed to us. + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const poolEntries = useMemo(() => { const seen = new Set(); const out: Array<{ id: string; source: string }> = []; @@ -718,6 +721,7 @@ export function PreviewPane({ onPickStarter }: PreviewPaneProps) { postClearPinToPreviewWindow(iframeRef.current?.contentWindow, pushIframeError); closeCommentBubble(); }; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const persistComment = async (text: string) => { const trimmed = text.trim(); if (!trimmed && !existingId) { diff --git a/apps/desktop/src/renderer/src/components/TopBar.tsx b/apps/desktop/src/renderer/src/components/TopBar.tsx index 74652606..97cdafcc 100644 --- a/apps/desktop/src/renderer/src/components/TopBar.tsx +++ b/apps/desktop/src/renderer/src/components/TopBar.tsx @@ -74,6 +74,7 @@ export function TopBar() { className="flex h-full min-w-max items-center gap-[var(--space-1)]" aria-label={t('hub.tabs.all')} > + {/* biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 */} {HUB_TABS.map((tab) => { const active = tab === hubTab; return ( diff --git a/apps/desktop/src/renderer/src/components/TweakPanel.tsx b/apps/desktop/src/renderer/src/components/TweakPanel.tsx index be3ca80b..f6fad310 100644 --- a/apps/desktop/src/renderer/src/components/TweakPanel.tsx +++ b/apps/desktop/src/renderer/src/components/TweakPanel.tsx @@ -29,6 +29,7 @@ export function shouldSyncPreviewSourceAfterTweakPersist(result: { wrote: boolea return !result.wrote; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function TokenRow({ tokenKey, value, diff --git a/apps/desktop/src/renderer/src/components/chat/ChatMessageList.tsx b/apps/desktop/src/renderer/src/components/chat/ChatMessageList.tsx index c22cb104..7b5c9ad4 100644 --- a/apps/desktop/src/renderer/src/components/chat/ChatMessageList.tsx +++ b/apps/desktop/src/renderer/src/components/chat/ChatMessageList.tsx @@ -28,6 +28,7 @@ interface RenderItem { * by a plain assistant prose bubble. Session-replayed history obeys the same * grouping because rows are read back in `seq` order. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function ChatMessageList({ messages, loading, diff --git a/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx b/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx index 12278ca0..348d78ee 100644 --- a/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx +++ b/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx @@ -150,27 +150,30 @@ function ActivityLedger({ rows }: { rows: ActivityRow[] }) { function extractTodos(call: ChatToolCallPayload): TodoItem[] { const raw = (call.args?.['todos'] as unknown) ?? (call.args?.['items'] as unknown) ?? null; if (!Array.isArray(raw)) return []; - return raw - .map((it): TodoItem | null => { - if (typeof it !== 'object' || it === null) return null; - const o = it as Record; - const text = - typeof o['content'] === 'string' - ? (o['content'] as string) - : typeof o['text'] === 'string' - ? (o['text'] as string) - : null; - if (text === null) return null; - const rawStatus = o['status']; - const status: TodoItem['status'] = - rawStatus === 'completed' || rawStatus === 'in_progress' || rawStatus === 'pending' - ? rawStatus - : o['checked'] === true - ? 'completed' - : 'pending'; - return { text, status }; - }) - .filter((x): x is TodoItem => x !== null); + return ( + raw + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 + .map((it): TodoItem | null => { + if (typeof it !== 'object' || it === null) return null; + const o = it as Record; + const text = + typeof o['content'] === 'string' + ? (o['content'] as string) + : typeof o['text'] === 'string' + ? (o['text'] as string) + : null; + if (text === null) return null; + const rawStatus = o['status']; + const status: TodoItem['status'] = + rawStatus === 'completed' || rawStatus === 'in_progress' || rawStatus === 'pending' + ? rawStatus + : o['checked'] === true + ? 'completed' + : 'pending'; + return { text, status }; + }) + .filter((x): x is TodoItem => x !== null) + ); } function isRecord(value: unknown): value is Record { @@ -400,6 +403,7 @@ function pushGenericToolRow(rows: ActivityRow[], call: ChatToolCallPayload, inde }); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function buildActivityRows(calls: ChatToolCallPayload[]): ActivityRow[] { const rows: ActivityRow[] = []; let lastFileRowIdx = -1; @@ -610,9 +614,9 @@ function ActivityTodoBlock({ row }: { row: ActivityRow }) { />
- {todos.map((todo, index) => ( + {todos.map((todo) => (
{todo.status === 'completed' ? ( diff --git a/apps/desktop/src/renderer/src/components/comment/CommentsPanel.tsx b/apps/desktop/src/renderer/src/components/comment/CommentsPanel.tsx index f642485c..3513041a 100644 --- a/apps/desktop/src/renderer/src/components/comment/CommentsPanel.tsx +++ b/apps/desktop/src/renderer/src/components/comment/CommentsPanel.tsx @@ -152,6 +152,7 @@ interface CommentItemProps { onRemove: () => void; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function CommentItem({ index, comment, diff --git a/apps/desktop/src/renderer/src/components/diagnostics/ReportEventDialog.tsx b/apps/desktop/src/renderer/src/components/diagnostics/ReportEventDialog.tsx index 7408c570..828b52fd 100644 --- a/apps/desktop/src/renderer/src/components/diagnostics/ReportEventDialog.tsx +++ b/apps/desktop/src/renderer/src/components/diagnostics/ReportEventDialog.tsx @@ -105,6 +105,7 @@ export interface PreviewLabels { * provider-scope events. Exported so the shape can be unit-tested without * mounting the dialog — the dialog just wraps this output in
.
  */
+// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
 export function formatPreview(
   error: ReportableError,
   opts: RedactOpts,
@@ -243,6 +244,7 @@ export function ReportEventDialog({ localId, onClose }: ReportEventDialogProps)
     if (localId === null) return;
     const dialog = dialogRef.current;
     if (!dialog) return;
+    // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
     function onKeyDown(e: KeyboardEvent) {
       if (e.key !== 'Tab') return;
       if (!dialog) return;
@@ -264,6 +266,7 @@ export function ReportEventDialog({ localId, onClose }: ReportEventDialogProps)
 
   if (localId === null || !error) return null;
 
+  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
   async function submit(kind: 'open' | 'copy') {
     if (!error) return;
     if (!validateNotes(notes)) {
diff --git a/apps/desktop/src/renderer/src/components/settings/ModelsTab.tsx b/apps/desktop/src/renderer/src/components/settings/ModelsTab.tsx
index 6e355fcd..928d6554 100644
--- a/apps/desktop/src/renderer/src/components/settings/ModelsTab.tsx
+++ b/apps/desktop/src/renderer/src/components/settings/ModelsTab.tsx
@@ -297,6 +297,7 @@ function AddProviderMenu({
   );
 }
 
+// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
 export function ModelsTab() {
   const t = useT();
   const config = useCodesignStore((s) => s.config);
@@ -373,6 +374,7 @@ export function ModelsTab() {
       .finally(() => setLoading(false));
     void window.codesign.config
       .detectExternalConfigs()
+      // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
       .then((detected) => {
         const dismissedCodex = readDismissed('codex');
         const dismissedClaudeCode = readDismissed('claudeCode');
@@ -549,6 +551,7 @@ export function ModelsTab() {
     }
   }
 
+  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
   async function handleImportOpencode() {
     if (!window.codesign) return;
     // Skipped-entry summary: OpenCode often has OAuth entries we skip; users
@@ -634,6 +637,7 @@ export function ModelsTab() {
     }
   }
 
+  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
   async function handleDelete(provider: string) {
     if (!window.codesign) return;
     try {
@@ -882,6 +886,7 @@ export function ModelsTab() {
                   );
                 })()}
               {externalConfigs.claudeCode !== undefined &&
+                // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
                 (() => {
                   const cc = externalConfigs.claudeCode;
                   const displayBaseUrl = maskBaseUrlCreds(cc.baseUrl);
diff --git a/apps/desktop/src/renderer/src/components/settings/primitives.tsx b/apps/desktop/src/renderer/src/components/settings/primitives.tsx
index 8c5e4e97..76b04959 100644
--- a/apps/desktop/src/renderer/src/components/settings/primitives.tsx
+++ b/apps/desktop/src/renderer/src/components/settings/primitives.tsx
@@ -553,6 +553,7 @@ export function ReasoningDepthSelector({
   }, [value]);
   const saveSeq = useRef(0);
 
+  // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118
   async function handleChange(next: ReasoningOption) {
     if (!window.codesign?.config?.updateProvider) return;
     const prev = current;
@@ -708,11 +709,9 @@ export function WarningsList({ warnings }: { warnings: string[] }) {
   const overflow = warnings.length - shown.length;
   return (
     
    - {shown.map((w, i) => ( - // Index-qualified key so two byte-identical warnings don't collide. - // eslint-disable-next-line react/no-array-index-key + {shown.map((w) => (
  • ⚠️ {w} diff --git a/apps/desktop/src/renderer/src/hooks/useAgentStream.ts b/apps/desktop/src/renderer/src/hooks/useAgentStream.ts index d40bf3cb..ec491cec 100644 --- a/apps/desktop/src/renderer/src/hooks/useAgentStream.ts +++ b/apps/desktop/src/renderer/src/hooks/useAgentStream.ts @@ -149,6 +149,7 @@ export function useAgentStream(): void { if (current) current.textBuffer = ''; }; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const handleToolCallStart = (event: AgentStreamEvent) => { const current = inFlight.current.get(event.generationId); const designId = event.designId; @@ -230,6 +231,7 @@ export function useAgentStream(): void { const result = event.result; const durationMs = event.durationMs; const finalStatus = event.status === 'error' ? 'error' : 'done'; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 void pending.seqPromise.then((seq) => { if (seq === null) return; void updateChatToolStatus({ @@ -245,6 +247,7 @@ export function useAgentStream(): void { }); }; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const handleFsUpdated = (event: AgentStreamEvent) => { markGenerationRunning(event.designId, event.generationId, 'streaming'); // Live mirror of the agent edit tool's mutations into the iframe. @@ -280,6 +283,7 @@ export function useAgentStream(): void { } }; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const handleError = (event: AgentStreamEvent) => { const current = inFlight.current.get(event.generationId); // TODO: replace with rendererLogger once renderer-logger lands @@ -322,6 +326,7 @@ export function useAgentStream(): void { } }; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const handleAgentEnd = (event: AgentStreamEvent) => { // Flush only this generation's pending preview updates before persisting // the final snapshot so concurrent background runs stay isolated. diff --git a/apps/desktop/src/renderer/src/hooks/useDesignFiles.ts b/apps/desktop/src/renderer/src/hooks/useDesignFiles.ts index b9c6d2ca..08a05aa2 100644 --- a/apps/desktop/src/renderer/src/hooks/useDesignFiles.ts +++ b/apps/desktop/src/renderer/src/hooks/useDesignFiles.ts @@ -151,6 +151,7 @@ export function useDesignFiles(designId: string | null): UseDesignFilesResult { ? 'workspace' : 'snapshots'; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const refetch = useCallback(async () => { const seq = ++refetchSeqRef.current; const isCurrent = () => refetchSeqRef.current === seq; @@ -426,6 +427,7 @@ export function useLazyDesignFileTree(designId: string | null): UseLazyDesignFil [backend, designId, dismissToast, pushToast, updateDirectories, workspacePath], ); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const reloadLoadedDirectories = useCallback(async () => { const seq = ++refetchSeqRef.current; const isCurrent = () => refetchSeqRef.current === seq; diff --git a/apps/desktop/src/renderer/src/store/lib/artifact.ts b/apps/desktop/src/renderer/src/store/lib/artifact.ts index 7ec3192a..46217778 100644 --- a/apps/desktop/src/renderer/src/store/lib/artifact.ts +++ b/apps/desktop/src/renderer/src/store/lib/artifact.ts @@ -1,5 +1,6 @@ import { findArtifactSourceReference } from '@open-codesign/runtime'; +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function delimiterDeltaOutsideStrings(src: string, open: string, close: string): number { let delta = 0; let inStr: '"' | "'" | '`' | null = null; diff --git a/apps/desktop/src/renderer/src/store/slices/chat.ts b/apps/desktop/src/renderer/src/store/slices/chat.ts index c43ff839..a32cf844 100644 --- a/apps/desktop/src/renderer/src/store/slices/chat.ts +++ b/apps/desktop/src/renderer/src/store/slices/chat.ts @@ -238,6 +238,7 @@ export function makeChatSlice(set: SetState, get: GetState): ChatSliceActions { set((s) => ({ pendingToolCalls: [...s.pendingToolCalls, call] })); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 resolvePendingToolCall(designId, toolName, result, durationMs) { const s = get(); const idx = s.pendingToolCalls.findIndex( @@ -309,6 +310,7 @@ export function makeChatSlice(set: SetState, get: GetState): ChatSliceActions { if (get().currentDesignId !== designId) return; set((s) => ({ chatMessages: compactChatRowsForUi( + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 s.chatMessages.map((m) => { if (m.designId !== designId || m.seq !== seq || m.kind !== 'tool_call') return m; const prev = (m.payload as ChatToolCallPayload | null) ?? null; @@ -375,6 +377,7 @@ export function makeChatSlice(set: SetState, get: GetState): ChatSliceActions { }); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async persistAgentRunSnapshot({ designId, finalText }) { if (!window.codesign) return; const state = get(); diff --git a/apps/desktop/src/renderer/src/store/slices/comments.ts b/apps/desktop/src/renderer/src/store/slices/comments.ts index a5ea6d5b..5dc513f0 100644 --- a/apps/desktop/src/renderer/src/store/slices/comments.ts +++ b/apps/desktop/src/renderer/src/store/slices/comments.ts @@ -83,6 +83,7 @@ export function makeCommentsSlice(set: SetState, get: GetState): CommentsSliceAc set({ liveRects: {} }); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async addComment(input) { if (!window.codesign) return null; const designId = get().currentDesignId; @@ -162,6 +163,7 @@ export function makeCommentsSlice(set: SetState, get: GetState): CommentsSliceAc } }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async submitComment(input) { // Route by presence of existingCommentId. The anchor on a reopened chip // carries the id, so editing text hits updateComment (no duplicate row); diff --git a/apps/desktop/src/renderer/src/store/slices/designs.ts b/apps/desktop/src/renderer/src/store/slices/designs.ts index c71ddba9..7717761f 100644 --- a/apps/desktop/src/renderer/src/store/slices/designs.ts +++ b/apps/desktop/src/renderer/src/store/slices/designs.ts @@ -181,6 +181,7 @@ export function makeDesignsSlice(set: SetState, get: GetState): DesignsSliceActi const state = get(); if (state.currentDesignId === id) { set({ designsViewOpen: false }); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 void (async () => { try { const snapshots = await window.codesign?.snapshots.list(id); @@ -245,6 +246,7 @@ export function makeDesignsSlice(set: SetState, get: GetState): DesignsSliceActi ); void get().loadChatForCurrentDesign(); void get().loadCommentsForCurrentDesign(); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 void (async () => { try { const snapshots = await window.codesign?.snapshots.list(id); @@ -289,6 +291,7 @@ export function makeDesignsSlice(set: SetState, get: GetState): DesignsSliceActi ); void get().loadChatForCurrentDesign(); void get().loadCommentsForCurrentDesign(); + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 void (async () => { try { const snapshots = await window.codesign?.snapshots.list(id); @@ -388,6 +391,7 @@ export function makeDesignsSlice(set: SetState, get: GetState): DesignsSliceActi } }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async softDeleteDesign(id: string) { if (!window.codesign) return; if (get().generationByDesign[id] !== undefined) { diff --git a/apps/desktop/src/renderer/src/store/slices/diagnostics.ts b/apps/desktop/src/renderer/src/store/slices/diagnostics.ts index 7e4f1fbc..de9d98a7 100644 --- a/apps/desktop/src/renderer/src/store/slices/diagnostics.ts +++ b/apps/desktop/src/renderer/src/store/slices/diagnostics.ts @@ -68,6 +68,7 @@ export function makeDiagnosticsSlice(set: SetState, get: GetState): DiagnosticsS set((s) => ({ toasts: s.toasts.filter((t) => t.id !== id) })); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 reportableErrorToast(spec) { if (spec.reportable === false) { return get().pushToast({ @@ -150,6 +151,7 @@ export function makeDiagnosticsSlice(set: SetState, get: GetState): DiagnosticsS }); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 createReportableError(partial) { const localId = newId(); const ts = Date.now(); diff --git a/apps/desktop/src/renderer/src/store/slices/generation.ts b/apps/desktop/src/renderer/src/store/slices/generation.ts index 35246415..b5e16de8 100644 --- a/apps/desktop/src/renderer/src/store/slices/generation.ts +++ b/apps/desktop/src/renderer/src/store/slices/generation.ts @@ -542,6 +542,7 @@ function buildGenerateReportContext( return Object.keys(context).length > 0 ? context : undefined; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function buildGenerateFixAction( get: GetState, set: SetState, @@ -718,6 +719,7 @@ export function makeGenerationSlice(set: SetState, get: GetState): GenerationSli }); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async sendPrompt(input) { recordAction({ type: 'prompt.submit', @@ -1040,6 +1042,7 @@ export function makeGenerationSlice(set: SetState, get: GetState): GenerationSli }); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async exportActive(format: ExportFormat) { recordAction({ type: 'design.export', data: { format } }); const source = get().previewSource; diff --git a/apps/desktop/src/renderer/src/store/slices/snapshots.ts b/apps/desktop/src/renderer/src/store/slices/snapshots.ts index e0368d84..4104b31d 100644 --- a/apps/desktop/src/renderer/src/store/slices/snapshots.ts +++ b/apps/desktop/src/renderer/src/store/slices/snapshots.ts @@ -122,6 +122,7 @@ export async function persistArtifactSnapshot( * only snapshot-era user prompts get backfilled. Falls back to [] when designId * is null or IPC is unavailable (renderer tests). */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function buildHistoryFromChat(designId: string | null): Promise { if (!designId || !window.codesign) return []; try { diff --git a/biome.json b/biome.json index 83d65646..495a5afc 100644 --- a/biome.json +++ b/biome.json @@ -53,9 +53,9 @@ "recommended": true, "suspicious": { "noExplicitAny": "error", - "noArrayIndexKey": "off", - "noAssignInExpressions": "off", - "noPrototypeBuiltins": "off", + "noArrayIndexKey": "error", + "noAssignInExpressions": "error", + "noPrototypeBuiltins": "error", "noDuplicateObjectKeys": "warn", "useIterableCallbackReturn": "off" }, @@ -65,10 +65,10 @@ "useLiteralEnumMembers": "off" }, "complexity": { - "noExcessiveCognitiveComplexity": "off", - "noForEach": "off", + "noExcessiveCognitiveComplexity": "error", + "noForEach": "error", "useLiteralKeys": "off", - "noCommaOperator": "off" + "noCommaOperator": "error" }, "correctness": { "useExhaustiveDependencies": "warn", @@ -77,12 +77,12 @@ "noUnusedVariables": "warn" }, "a11y": { - "useButtonType": "off", - "useFocusableInteractive": "off", - "useSemanticElements": "off", - "noSvgWithoutTitle": "off", - "useKeyWithClickEvents": "off", - "useValidAnchor": "off", + "useButtonType": "error", + "useFocusableInteractive": "error", + "useSemanticElements": "error", + "noSvgWithoutTitle": "error", + "useKeyWithClickEvents": "error", + "useValidAnchor": "error", "useAriaPropsForRole": "off", "useAriaPropsSupportedByRole": "off", "noStaticElementInteractions": "off" diff --git a/packages/artifacts/src/parser.ts b/packages/artifacts/src/parser.ts index 03266309..ed4e977a 100644 --- a/packages/artifacts/src/parser.ts +++ b/packages/artifacts/src/parser.ts @@ -74,6 +74,7 @@ export function createArtifactParser() { return out; } + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function* feed(delta: string): Generator { state.buffer += delta; @@ -175,6 +176,7 @@ export function createArtifactParser() { * must hold back from `start` and wait for more input * - `none`: no candidate; caller may flush the entire buffer as text */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function findOpenTag(buffer: string): OpenTagMatch { let from = 0; while (from <= buffer.length) { diff --git a/packages/core/src/agent.test.ts b/packages/core/src/agent.test.ts index 6e343690..617f18f7 100644 --- a/packages/core/src/agent.test.ts +++ b/packages/core/src/agent.test.ts @@ -108,6 +108,7 @@ vi.mock('@mariozechner/pi-agent-core', () => { this.call.listeners.push((e) => listener(e)); return () => {}; } + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async prompt(message: unknown, images?: unknown[]): Promise { this.call.prompts.push({ message, images }); const callIndex = agentCalls.indexOf(this.call); diff --git a/packages/core/src/agent.ts b/packages/core/src/agent.ts index d4e2121a..0fd2bb2a 100644 --- a/packages/core/src/agent.ts +++ b/packages/core/src/agent.ts @@ -847,6 +847,7 @@ function sourceCandidates( .slice(0, 8); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function buildWorkspaceBrief( input: GenerateInput, fs: TextEditorFsCallbacks | undefined, @@ -985,6 +986,7 @@ export interface GenerateViaAgentDeps { * tool surface. Events are emitted so the desktop shell can stream progress, * tool calls, and file updates while preserving the GenerateOutput boundary. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function generateViaAgent( input: GenerateInput, deps: GenerateViaAgentDeps = {}, diff --git a/packages/core/src/brand/tailwindExtractor.ts b/packages/core/src/brand/tailwindExtractor.ts index a77768e1..251447af 100644 --- a/packages/core/src/brand/tailwindExtractor.ts +++ b/packages/core/src/brand/tailwindExtractor.ts @@ -60,6 +60,7 @@ function extractAllSectionBodies(source: string, sectionKey: string): string[] { // Extract the body of a `{` brace at position `bracePos` in `text`. // Quote- and comment-aware so braces inside strings or comments do not // terminate blocks early. +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function extractBodyAt(text: string, bracePos: number): string | null { if (text[bracePos] !== '{') return null; @@ -149,6 +150,7 @@ function leafValueFromMatch(m: RegExpMatchArray): string | undefined { // Walk object literal text and collect leaf key→value pairs. // Only extracts simple string literals and string arrays; skips functions and spreads. +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function collectLeafPairs(body: string, prefix: string): Array<{ name: string; value: string }> { const results: Array<{ name: string; value: string }> = []; diff --git a/packages/core/src/context-prune.ts b/packages/core/src/context-prune.ts index a9485681..e6057ff6 100644 --- a/packages/core/src/context-prune.ts +++ b/packages/core/src/context-prune.ts @@ -123,6 +123,7 @@ function compactAssistant( }; if (!Array.isArray(original.content)) return m; let changed = false; + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 const nextContent = original.content.map((block) => { const type = block?.['type']; if (type === 'text') { diff --git a/packages/core/src/design-context.ts b/packages/core/src/design-context.ts index eea46aa2..df1af4bd 100644 --- a/packages/core/src/design-context.ts +++ b/packages/core/src/design-context.ts @@ -254,6 +254,7 @@ function historyBudgetChars(input: BuildDesignContextPackInput): number { return DEFAULT_HISTORY_BUDGET_CHARS; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function selectBudgetedHistory( messages: ChatMessage[], budget: number, @@ -392,6 +393,7 @@ function stripJsonFence(raw: string): string { return fenced?.[1]?.trim() ?? trimmed; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function updateDesignSessionBrief( input: UpdateDesignSessionBriefInput, ): Promise { diff --git a/packages/core/src/lib/context-format.ts b/packages/core/src/lib/context-format.ts index 9880da45..b4ac5af0 100644 --- a/packages/core/src/lib/context-format.ts +++ b/packages/core/src/lib/context-format.ts @@ -98,6 +98,7 @@ export function formatReferenceUrl( ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function buildContextSections(input: { sessionContext?: string[] | undefined; designSystem?: StoredDesignSystem | null | undefined; diff --git a/packages/core/src/memory.ts b/packages/core/src/memory.ts index ab7e41e3..a57a2acb 100644 --- a/packages/core/src/memory.ts +++ b/packages/core/src/memory.ts @@ -35,6 +35,7 @@ function extractTextFromContent(content: unknown): string { return parts.join('\n'); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function serializeMessagesForMemory(messages: AgentMessage[]): string { const lines: string[] = []; for (const msg of messages) { diff --git a/packages/core/src/resource-manifest.ts b/packages/core/src/resource-manifest.ts index 9a2da291..222e0ebf 100644 --- a/packages/core/src/resource-manifest.ts +++ b/packages/core/src/resource-manifest.ts @@ -216,6 +216,7 @@ export function formatResourceManifestForPrompt(manifest: ResourceManifestV1): s ].join('\n'); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function collectResourceManifest(input: { log: CoreLogger; providerId: string; diff --git a/packages/core/src/run-preferences.ts b/packages/core/src/run-preferences.ts index a8fa941a..cfc96386 100644 --- a/packages/core/src/run-preferences.ts +++ b/packages/core/src/run-preferences.ts @@ -147,6 +147,7 @@ function isRecord(value: unknown): value is Record { return typeof value === 'object' && value !== null && !Array.isArray(value); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function normalizeQuestions(raw: unknown): AskInput['questions'] | undefined { if (!Array.isArray(raw)) return undefined; const questions: AskInput['questions'] = []; @@ -228,6 +229,7 @@ export function normalizeRunPreferencesRouterResult( }; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function applyRunPreferenceAnswers( base: DesignRunPreferencesV1, answers: Array<{ questionId: string; value: string | number | string[] | null }>, @@ -272,6 +274,7 @@ export function runPreferencesFromJson( } } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function routeRunPreferences( input: RouteRunPreferencesInput, ): Promise { diff --git a/packages/core/src/tools/ask.ts b/packages/core/src/tools/ask.ts index e165d3c8..5fa96daf 100644 --- a/packages/core/src/tools/ask.ts +++ b/packages/core/src/tools/ask.ts @@ -142,6 +142,7 @@ function assertKnownQuestionFields( : { ok: false, reason: `unsupported field: ${unsupported}` }; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function validateAskQuestion( question: unknown, ): { ok: true; id: string } | { ok: false; reason: string } { diff --git a/packages/core/src/tools/done.ts b/packages/core/src/tools/done.ts index 6763fdb6..f768f3b9 100644 --- a/packages/core/src/tools/done.ts +++ b/packages/core/src/tools/done.ts @@ -304,6 +304,7 @@ function shouldStartStringLiteral(src: string, index: number): boolean { * Only fires for JSX-shaped artifacts. Pure HTML (legacy pastes, tests) is * skipped — those have their own checks via findUnclosedTags etc. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function findJsxStructuralIssues(src: string): DoneError[] { // Plain HTML files are first-class for legacy sources and imported files. // New generated designs default to App.jsx, but HTML should not be coerced @@ -465,6 +466,7 @@ export function makeDoneTool( 'remain with a valid artifact after those repair rounds, the host may ' + 'keep the latest artifact but will surface warnings to the user.', parameters: DoneParams, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async execute(_id, params): Promise> { const path = resolveDonePath(fs, params.path); const file = fs.view(path); diff --git a/packages/core/src/tools/generate-image-asset.ts b/packages/core/src/tools/generate-image-asset.ts index a0126a97..788fd401 100644 --- a/packages/core/src/tools/generate-image-asset.ts +++ b/packages/core/src/tools/generate-image-asset.ts @@ -129,6 +129,7 @@ export function makeGenerateImageAssetTool( `so prefer batching all needed assets in one assistant turn before writing ${DEFAULT_SOURCE_ENTRY}. ` + 'The tool returns a local assets/... path to reference.', parameters: GenerateImageAssetParams, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async execute( _toolCallId, params, diff --git a/packages/core/src/tools/scaffold.ts b/packages/core/src/tools/scaffold.ts index 36a206a8..20400e0e 100644 --- a/packages/core/src/tools/scaffold.ts +++ b/packages/core/src/tools/scaffold.ts @@ -48,6 +48,7 @@ function parseStringArray(value: unknown, field: string): string[] { return out; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function parseScaffoldManifest(value: unknown): ScaffoldManifest { if (!isRecord(value)) { throw new Error('manifest must be an object'); @@ -183,6 +184,7 @@ function destinationPathForSource(destPath: string, sourcePath: string): string return path.posix.join(parsed.dir, `${parsed.name}${sourceExt}`); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function runScaffold(req: ScaffoldRequest): Promise { let manifest: ScaffoldManifest; try { @@ -289,6 +291,7 @@ export function makeScaffoldTool( description: "Copy a concrete starter/source asset into the current workspace. kind: one of the keys in /templates/scaffolds/manifest.json (device-frame / browser / app-shell / dev-mockup / ui-primitive / background / surface / deck / report / design-system / landing). destPath: workspace-relative path. Example: scaffold({kind: 'iphone-16-pro-frame', destPath: 'frames/iphone.jsx'}). The tool preserves the source extension.", parameters: ScaffoldParams, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async execute(_toolCallId, params): Promise> { const workspaceRoot = getWorkspaceRoot(); if (!workspaceRoot) { diff --git a/packages/core/src/tools/skill.ts b/packages/core/src/tools/skill.ts index d8483a3a..7de4f12e 100644 --- a/packages/core/src/tools/skill.ts +++ b/packages/core/src/tools/skill.ts @@ -75,6 +75,7 @@ function rootForEntry(entry: SkillManifestEntry, roots: SkillRoots): string | nu return roots.brandRefsRoot ?? null; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function listSkillManifest(roots: SkillRoots): Promise { const out: SkillManifestEntry[] = []; @@ -241,6 +242,7 @@ export function makeSkillTool( 'does not copy scaffold files. One call per skill per session; repeat ' + 'calls return a short already-loaded response.', parameters: SkillParams, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async execute(_toolCallId, params): Promise> { const name = params.name; const result = await invokeSkill({ diff --git a/packages/core/src/tools/text-editor.ts b/packages/core/src/tools/text-editor.ts index a8f75738..ccc7a6b2 100644 --- a/packages/core/src/tools/text-editor.ts +++ b/packages/core/src/tools/text-editor.ts @@ -169,6 +169,7 @@ export function makeTextEditorTool( 'to read only a slice of the file — strongly preferred over full-file views after the file has grown past ~100 lines. ' + 'Without view_range, repeated `view` of the same path within a single run returns only a short summary to protect context.', parameters: TextEditorParams, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async execute(_toolCallId, params): Promise> { const path = normalizeToolPath(params.path); switch (params.command) { diff --git a/packages/core/src/tools/verify-ui-kit-parity.ts b/packages/core/src/tools/verify-ui-kit-parity.ts index 33018221..19ab2650 100644 --- a/packages/core/src/tools/verify-ui-kit-parity.ts +++ b/packages/core/src/tools/verify-ui-kit-parity.ts @@ -210,6 +210,7 @@ export function makeVerifyUiKitParityTool( '0.85, re-call decompose_to_ui_kit with adjustments that address the gaps list ' + 'returned by this tool. No LLM judge involved — the result is reproducible.', parameters: VerifyParams, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async execute(_toolCallId, params, _signal): Promise> { const sourcePath = params.sourcePath ?? 'index.html'; const decomposedPath = `ui_kits/${params.slug}/index.html`; diff --git a/packages/core/src/tools/verify-ui-kit-visual-parity.ts b/packages/core/src/tools/verify-ui-kit-visual-parity.ts index 462e07c5..3f5f82eb 100644 --- a/packages/core/src/tools/verify-ui-kit-visual-parity.ts +++ b/packages/core/src/tools/verify-ui-kit-visual-parity.ts @@ -262,6 +262,7 @@ export function makeVerifyUiKitVisualParityTool( 'decompose_to_ui_kit addressing the failed-check reasons. If this tool ' + 'returns status="unavailable", proceed with the deterministic verifier alone.', parameters: VerifyParams, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async execute(_toolCallId, params, signal): Promise> { const startedAt = Date.now(); const decomposedPath = `ui_kits/${params.slug}/index.html`; diff --git a/packages/exporters/src/assets.ts b/packages/exporters/src/assets.ts index 4ae24da2..b3a40343 100644 --- a/packages/exporters/src/assets.ts +++ b/packages/exporters/src/assets.ts @@ -102,6 +102,7 @@ export async function collectLocalAssetsFromHtml( } } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function rewriteHtmlLocalAssetReferences( html: string, opts: LocalAssetOptions = {}, diff --git a/packages/exporters/src/chrome-discovery.ts b/packages/exporters/src/chrome-discovery.ts index 4a9e5c1f..567a3e8c 100644 --- a/packages/exporters/src/chrome-discovery.ts +++ b/packages/exporters/src/chrome-discovery.ts @@ -53,6 +53,7 @@ export async function findSystemChrome(deps: ChromeDiscoveryDeps = {}): Promise< ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function locate(d: { platform: NodeJS.Platform; env: NodeJS.ProcessEnv; diff --git a/packages/exporters/src/html.ts b/packages/exporters/src/html.ts index 91b6cc40..6224d700 100644 --- a/packages/exporters/src/html.ts +++ b/packages/exporters/src/html.ts @@ -125,6 +125,7 @@ function injectIntoHead(html: string, tag: string): string { * reflows indentation. We deliberately avoid pulling in `prettier` / * `js-beautify` (would blow the dep budget) — Tier 2 can swap this out. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function prettifyHtml(html: string): string { const protectedHtml = protectRawTextBlocks(html); const tokens = protectedHtml.html.replace(/>\s+<').replace(/>\n<').split('\n'); diff --git a/packages/exporters/src/pdf.ts b/packages/exporters/src/pdf.ts index 232c1a35..944ea659 100644 --- a/packages/exporters/src/pdf.ts +++ b/packages/exporters/src/pdf.ts @@ -59,6 +59,7 @@ const DEFAULT_VIEWPORT = { width: 1280, height: 800 } as const; * avoid Puppeteer's full distribution (~150 MB Chromium download) — `puppeteer-core` * connects to the system Chrome we discover at runtime. PRINCIPLES §1 + §10. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function exportPdf( artifactSource: string, destinationPath: string, diff --git a/packages/exporters/src/pptx.ts b/packages/exporters/src/pptx.ts index e1c6b271..0ebcb354 100644 --- a/packages/exporters/src/pptx.ts +++ b/packages/exporters/src/pptx.ts @@ -57,6 +57,7 @@ const DEFAULT_FALLBACK_SLIDE_SELECTOR: string = * keeping pptxgenjs' default `wrap=square` and explicitly enabling * `fit: 'shrink'` (emits `normAutofit`). Verified with PowerPoint Mac. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function exportPptx( artifactSource: string, destinationPath: string, @@ -135,6 +136,7 @@ export async function exportPptx( } } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 async function renderSlideScreenshots( artifactSource: string, opts: ExportPptxOptions, @@ -267,27 +269,33 @@ const PARAGRAPH_RE = /]*>([\s\S]*?)<\/p>/gi; export function extractSlides(html: string): SlideContent[] { const sections: string[] = []; - let m: RegExpExecArray | null; - while ((m = SECTION_RE.exec(html)) !== null) sections.push(m[1] ?? ''); + let m = SECTION_RE.exec(html); + while (m !== null) { + sections.push(m[1] ?? ''); + m = SECTION_RE.exec(html); + } if (sections.length === 0) sections.push(html); return sections.map(parseSlide); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function parseSlide(fragment: string): SlideContent { const headingMatch = HEADING_RE.exec(fragment); const title = headingMatch ? stripHtml(headingMatch[1] ?? '') : ''; const bullets: string[] = []; - let li: RegExpExecArray | null; - while ((li = LIST_ITEM_RE.exec(fragment)) !== null) { + let li = LIST_ITEM_RE.exec(fragment); + while (li !== null) { const text = stripHtml(li[1] ?? ''); if (text) bullets.push(text); + li = LIST_ITEM_RE.exec(fragment); } if (bullets.length === 0) { - let p: RegExpExecArray | null; - while ((p = PARAGRAPH_RE.exec(fragment)) !== null) { + let p = PARAGRAPH_RE.exec(fragment); + while (p !== null) { const text = stripHtml(p[1] ?? ''); if (text) bullets.push(text); + p = PARAGRAPH_RE.exec(fragment); } } if (bullets.length === 0 && !title) { diff --git a/packages/exporters/src/zip.ts b/packages/exporters/src/zip.ts index 753d0c4d..6d395c9c 100644 --- a/packages/exporters/src/zip.ts +++ b/packages/exporters/src/zip.ts @@ -57,6 +57,7 @@ This bundle was exported from [open-codesign](https://github.com/OpenCoworkAI/op * MIT, zero deps, and handles streamed writes without buffering the whole * archive in memory (PRINCIPLES §1). */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function exportZip( artifactSource: string, destinationPath: string, diff --git a/packages/providers/src/images.ts b/packages/providers/src/images.ts index 5718afe5..0d31f66b 100644 --- a/packages/providers/src/images.ts +++ b/packages/providers/src/images.ts @@ -104,6 +104,7 @@ export async function generateImage(options: GenerateImageOptions): Promise { @@ -300,6 +301,7 @@ async function postChatGPTCodexImageStream( ); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function parseChatGPTCodexImageStream( text: string, ): { base64: string; revisedPrompt?: string | undefined } | null { @@ -450,6 +452,7 @@ function resolveCodexResponsesEndpoint(baseUrl: string): string { return `${normalized}/codex/responses`; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function extractChatGPTAccountId(token: string): string { const claims = decodeJwtClaims(token); const topLevel = readNonEmptyString(claims?.['chatgpt_account_id']); diff --git a/packages/providers/src/index.ts b/packages/providers/src/index.ts index 34cfdf70..728d17c6 100644 --- a/packages/providers/src/index.ts +++ b/packages/providers/src/index.ts @@ -344,6 +344,7 @@ function synthesizeWireModel( * * Lazy-imports pi-ai so the bundle is not loaded at app startup. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function complete( model: ModelRef, messages: ChatMessage[], diff --git a/packages/providers/src/retry.ts b/packages/providers/src/retry.ts index b192301c..e0be7692 100644 --- a/packages/providers/src/retry.ts +++ b/packages/providers/src/retry.ts @@ -306,6 +306,7 @@ export interface BackoffOptions { * when you need first-turn retry semantics around an arbitrary transient-prone * async op (e.g. `agent.prompt()` in the pi-agent-core path). */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export async function withBackoff(fn: () => Promise, opts: BackoffOptions = {}): Promise { const maxRetries = opts.maxRetries ?? DEFAULT_MAX_RETRIES; const baseDelayMs = opts.baseDelayMs ?? DEFAULT_BASE_DELAY_MS; diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 9caac56b..b8a4fe41 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -147,6 +147,7 @@ function isIdentifierBoundary(ch: string | undefined): boolean { return ch === undefined || !/[A-Za-z0-9_$]/u.test(ch); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function containsNamedDeclaration(source: string, name: 'App' | '_App'): boolean { for (const keyword of ['function', 'const', 'let']) { let index = source.indexOf(keyword); diff --git a/packages/runtime/src/overlay.test.ts b/packages/runtime/src/overlay.test.ts index 17650392..e2004dbe 100644 --- a/packages/runtime/src/overlay.test.ts +++ b/packages/runtime/src/overlay.test.ts @@ -284,6 +284,7 @@ function runOverlayForRects(): RectHarness { style: {}, }); }, + // biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 registerBodyPath: (selector, rect) => { const parts = selector.slice(1).split('/'); let current = body; diff --git a/packages/shared/src/design-md.ts b/packages/shared/src/design-md.ts index 1a262c5e..bda8eff0 100644 --- a/packages/shared/src/design-md.ts +++ b/packages/shared/src/design-md.ts @@ -184,6 +184,7 @@ function validateColors(findings: DesignMdFinding[], value: unknown): void { } } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function validateTypography(findings: DesignMdFinding[], value: unknown): void { if (!isRecord(value)) { findings.push( diff --git a/packages/shared/src/diagnostics.ts b/packages/shared/src/diagnostics.ts index bf3008f0..887dc697 100644 --- a/packages/shared/src/diagnostics.ts +++ b/packages/shared/src/diagnostics.ts @@ -116,6 +116,7 @@ function stripModelsPrefix(modelId: string): string { * Map an ErrorCode + context to one or more DiagnosticHypothesis items. * The first item is the "most likely" cause; subsequent items are alternatives. */ +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function diagnose(code: ErrorCode, ctx: DiagnoseContext): DiagnosticHypothesis[] { // Normalise the code — some callers pass the HTTP status as a string like "404" const normalised = String(code).toUpperCase(); @@ -332,6 +333,7 @@ function mentionsModelsPrefix(message: string): boolean { return /\bmodels\/[-._:/a-z0-9]+\b/i.test(message); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function diagnoseGenerateFailure(ctx: GenerateFailureContext): DiagnosticHypothesis[] { const message = (ctx.message ?? '').toLowerCase(); const status = ctx.status; diff --git a/packages/shared/src/editmode.ts b/packages/shared/src/editmode.ts index a16ebe32..4bc0640e 100644 --- a/packages/shared/src/editmode.ts +++ b/packages/shared/src/editmode.ts @@ -238,7 +238,7 @@ function isPlainObject(value: unknown): value is Record { } function hasOwn(value: Record, key: string): boolean { - return Object.prototype.hasOwnProperty.call(value, key); + return Object.hasOwn(value, key); } function optionalNumber(value: Record, key: string): number | null | undefined { @@ -251,6 +251,7 @@ function isStringArray(value: unknown[]): value is string[] { return value.every((option) => typeof option === 'string'); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 function validateEntry(value: unknown): TokenSchemaEntry | null { if (!isPlainObject(value)) return null; const kind = value['kind']; diff --git a/packages/shared/src/html-utils.ts b/packages/shared/src/html-utils.ts index ba8a7366..b8796108 100644 --- a/packages/shared/src/html-utils.ts +++ b/packages/shared/src/html-utils.ts @@ -69,6 +69,7 @@ export function decodeHtmlEntities(input: string): string { return out; } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function stripHtmlTags(input: string): string { let out = ''; let inTag = false; @@ -197,6 +198,7 @@ export function extractHtmlElementInner(html: string, tagName: string): string | return html.slice(openEnd, closeStart); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function getHtmlAttribute(tagAttrs: string, attrName: string): string | null { const name = attrName.toLowerCase(); let index = 0; diff --git a/packages/shared/src/resource-manifest.ts b/packages/shared/src/resource-manifest.ts index 6631e05d..865b7877 100644 --- a/packages/shared/src/resource-manifest.ts +++ b/packages/shared/src/resource-manifest.ts @@ -110,6 +110,7 @@ function addUnique(target: string[], value: string): void { if (!target.includes(value)) target.push(value); } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function applyToolCallToResourceState( state: ResourceStateV1, call: ChatToolCallPayload, @@ -182,6 +183,7 @@ export function applyToolCallToResourceState( } } +// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: existing complexity, see #118 export function deriveResourceStateFromChatRows(rows: readonly ChatMessageRow[]): ResourceStateV1 { const state = createEmptyResourceState(); for (const row of rows) {