From ea371bc7ed86769286947181e4c4374382954fda Mon Sep 17 00:00:00 2001 From: yue <125123863+mmmself@users.noreply.github.com> Date: Sun, 5 Jul 2026 17:40:01 +0800 Subject: [PATCH 1/2] fix: re-enable noArrayIndexKey, noPrototypeBuiltins, noCommaOperator lint rules Closes #118 (partial) - Enable suspicious/noArrayIndexKey, suspicious/noPrototypeBuiltins, complexity/noCommaOperator as error in biome.json - Replace Object.prototype.hasOwnProperty.call() with Object.hasOwn() in editmode.ts - Fix noArrayIndexKey in FilesTabView.tsx (suppress with biome-ignore for static document lines) - Fix noArrayIndexKey in WorkingCard.tsx (use todo.text as stable key) - Fix noArrayIndexKey in primitives.tsx (use warning text as key, remove stale eslint-disable comments) - noCommaOperator: zero violations already, rule enabled cleanly --- apps/desktop/src/renderer/src/components/FilesTabView.tsx | 1 + .../src/renderer/src/components/chat/WorkingCard.tsx | 4 ++-- .../src/renderer/src/components/settings/primitives.tsx | 6 ++---- biome.json | 6 +++--- packages/shared/src/editmode.ts | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/apps/desktop/src/renderer/src/components/FilesTabView.tsx b/apps/desktop/src/renderer/src/components/FilesTabView.tsx index 5e7c0c6d..151ab983 100644 --- a/apps/desktop/src/renderer/src/components/FilesTabView.tsx +++ b/apps/desktop/src/renderer/src/components/FilesTabView.tsx @@ -1307,6 +1307,7 @@ function DocumentFilePreview({
{line}
diff --git a/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx b/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx index 12278ca0..2033cd29 100644 --- a/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx +++ b/apps/desktop/src/renderer/src/components/chat/WorkingCard.tsx @@ -610,9 +610,9 @@ function ActivityTodoBlock({ row }: { row: ActivityRow }) { />.
*/
+// 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 a233ed6a..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;
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 71a6b96e..495a5afc 100644
--- a/biome.json
+++ b/biome.json
@@ -54,7 +54,7 @@
"suspicious": {
"noExplicitAny": "error",
"noArrayIndexKey": "error",
- "noAssignInExpressions": "off",
+ "noAssignInExpressions": "error",
"noPrototypeBuiltins": "error",
"noDuplicateObjectKeys": "warn",
"useIterableCallbackReturn": "off"
@@ -65,8 +65,8 @@
"useLiteralEnumMembers": "off"
},
"complexity": {
- "noExcessiveCognitiveComplexity": "off",
- "noForEach": "off",
+ "noExcessiveCognitiveComplexity": "error",
+ "noForEach": "error",
"useLiteralKeys": "off",
"noCommaOperator": "error"
},
@@ -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 e7fb6727..4bc0640e 100644
--- a/packages/shared/src/editmode.ts
+++ b/packages/shared/src/editmode.ts
@@ -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) {