diff --git a/packages/agent/src/agent.ts b/packages/agent/src/agent.ts index 904d1b298..e6ca71b8f 100644 --- a/packages/agent/src/agent.ts +++ b/packages/agent/src/agent.ts @@ -1108,7 +1108,7 @@ export class Agent { /** Calculate total text length from an assistant message's content blocks */ #getAssistantTextLength(message: AgentMessage | null): number { - if (!message || message.role !== "assistant" || !Array.isArray(message.content)) { + if (message?.role !== "assistant" || !Array.isArray(message.content)) { return 0; } let length = 0; diff --git a/packages/agent/src/harmony-leak.ts b/packages/agent/src/harmony-leak.ts index 545c8e16e..6d59e5f26 100644 --- a/packages/agent/src/harmony-leak.ts +++ b/packages/agent/src/harmony-leak.ts @@ -230,7 +230,7 @@ export function recoverHarmonyToolCall( ): HarmonyRecoveredToolCall | undefined { if (detection.surface !== "tool_arg" || detection.contentIndex === undefined) return undefined; const block = message.content[detection.contentIndex]; - if (!block || block.type !== "toolCall") return undefined; + if (block?.type !== "toolCall") return undefined; const config = RECOVERY_REGISTRY[block.name]; if (!config) return undefined; diff --git a/packages/agent/test/agent-loop.test.ts b/packages/agent/test/agent-loop.test.ts index af0e6e267..815a748ad 100644 --- a/packages/agent/test/agent-loop.test.ts +++ b/packages/agent/test/agent-loop.test.ts @@ -334,7 +334,7 @@ describe("agentLoop with AgentMessage", () => { } const partial = makeMessage(index); const toolCall = partial.content[index - 1]; - if (!toolCall || toolCall.type !== "toolCall") throw new Error("Expected tool call"); + if (toolCall?.type !== "toolCall") throw new Error("Expected tool call"); stream.push({ type: "toolcall_start", contentIndex: index - 1, partial }); stream.push({ type: "toolcall_delta", @@ -371,7 +371,7 @@ describe("agentLoop with AgentMessage", () => { event.type === "turn_end" && event.toolResults.length === 8, ); expect(batchedTurn).toBeDefined(); - if (!batchedTurn || batchedTurn.message.role !== "assistant") return; + if (batchedTurn?.message.role !== "assistant") return; expect(batchedTurn.message.stopReason).toBe("toolUse"); expect(batchedTurn.message.content.filter(block => block.type === "toolCall")).toHaveLength(8); expect(batchedTurn.toolResults.map(result => result.toolCallId).sort()).toEqual([ @@ -571,7 +571,7 @@ describe("agentLoop with AgentMessage", () => { e.type === "message_end" && e.message.role === "toolResult", ); expect(toolResultEvent).toBeDefined(); - if (!toolResultEvent || toolResultEvent.message.role !== "toolResult") return; + if (toolResultEvent?.message.role !== "toolResult") return; expect(toolResultEvent.message.isError).toBe(true); expect(toolResultEvent.message.toolCallId).toBe("tool-1"); expect(toolResultEvent.message.content[0]?.type).toBe("text"); diff --git a/packages/ai/src/auth-broker/remote-store.ts b/packages/ai/src/auth-broker/remote-store.ts index a11898e67..27388cf66 100644 --- a/packages/ai/src/auth-broker/remote-store.ts +++ b/packages/ai/src/auth-broker/remote-store.ts @@ -281,7 +281,7 @@ export class RemoteAuthCredentialStore implements AuthCredentialStore { async prepareForRequest(credentialId: number, opts: { signal?: AbortSignal } = {}): Promise { const entry = this.#snapshot.credentials.find(candidate => candidate.id === credentialId); - if (!entry || entry.credential.type !== "oauth" || entry.rotatesInMs === null) return false; + if (entry?.credential.type !== "oauth" || entry.rotatesInMs === null) return false; const remainingMs = this.#snapshotReceivedAt + entry.rotatesInMs - Date.now(); if (remainingMs > WAIT_THRESHOLD_MS) return false; return this.waitForFreshSnapshot(MAX_WAIT_MS, opts); diff --git a/packages/ai/src/auth-storage.ts b/packages/ai/src/auth-storage.ts index 92bdc4e0c..65549e02f 100644 --- a/packages/ai/src/auth-storage.ts +++ b/packages/ai/src/auth-storage.ts @@ -2984,7 +2984,7 @@ export class AuthStorage { if (!prepare) return true; const stored = this.#getStoredCredentials(provider); const selected = stored[selection.index]; - if (!selected || selected.credential.type !== "oauth") return false; + if (selected?.credential.type !== "oauth") return false; const prepared = await prepare(selected.id, { signal: options?.signal }); if (!prepared) return true; @@ -2996,7 +2996,7 @@ export class AuthStorage { const latestIndex = latestRows.findIndex(row => row.id === selected.id); if (latestIndex === -1) return false; const latest = latestRows[latestIndex]; - if (!latest || latest.credential.type !== "oauth") return false; + if (latest?.credential.type !== "oauth") return false; selection.index = latestIndex; selection.credential = latest.credential; return true; diff --git a/packages/ai/src/providers/anthropic.ts b/packages/ai/src/providers/anthropic.ts index e1f6e0816..97cade192 100644 --- a/packages/ai/src/providers/anthropic.ts +++ b/packages/ai/src/providers/anthropic.ts @@ -1775,7 +1775,7 @@ function disableThinkingIfToolChoiceForced(params: MessageCreateParamsStreaming) function ensureMaxTokensForThinking(params: MessageCreateParamsStreaming, model: Model<"anthropic-messages">): void { const thinking = params.thinking; - if (!thinking || thinking.type !== "enabled") return; + if (thinking?.type !== "enabled") return; const budgetTokens = thinking.budget_tokens ?? 0; if (budgetTokens <= 0) return; diff --git a/packages/ai/src/providers/openai-completions.ts b/packages/ai/src/providers/openai-completions.ts index b33157223..0a6b8ac4b 100644 --- a/packages/ai/src/providers/openai-completions.ts +++ b/packages/ai/src/providers/openai-completions.ts @@ -586,7 +586,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = ( eventStream: AssistantMessageEventStream, text: string, ): void => { - if (!currentBlock || currentBlock.type !== "text") { + if (currentBlock?.type !== "text") { finishCurrentBlock(currentBlock); currentBlock = { type: "text", text: "" }; message.content.push(currentBlock); @@ -607,8 +607,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = ( signature?: string, ): void => { if ( - !currentBlock || - currentBlock.type !== "thinking" || + currentBlock?.type !== "thinking" || (signature !== undefined && currentBlock.thinkingSignature !== signature) ) { finishCurrentBlock(currentBlock); @@ -815,7 +814,7 @@ export const streamOpenAICompletions: StreamFunction<"openai-completions"> = ( } if (!block) { - if (!currentBlock || currentBlock.type !== "toolCall") { + if (currentBlock?.type !== "toolCall") { finishCurrentBlock(currentBlock); } block = { diff --git a/packages/ai/src/providers/openai-responses-server.ts b/packages/ai/src/providers/openai-responses-server.ts index 7fe25b9be..7fe0c3bf5 100644 --- a/packages/ai/src/providers/openai-responses-server.ts +++ b/packages/ai/src/providers/openai-responses-server.ts @@ -954,7 +954,7 @@ export function encodeStream( break; } case "text_delta": { - if (!state.open || state.open.kind !== "message") break; + if (state.open?.kind !== "message") break; const cur: OpenMessage = state.open; cur.currentPartText += ev.delta; emit("response.output_text.delta", { @@ -970,7 +970,7 @@ export function encodeStream( break; } case "text_end": { - if (!state.open || state.open.kind !== "message") break; + if (state.open?.kind !== "message") break; const cur: OpenMessage = state.open; const text = ev.content ?? cur.currentPartText; emit("response.output_text.done", { @@ -997,7 +997,7 @@ export function encodeStream( break; } case "thinking_delta": { - if (!state.open || state.open.kind !== "reasoning") break; + if (state.open?.kind !== "reasoning") break; const cur: OpenReasoning = state.open; cur.reasoningText += ev.delta; emit("response.reasoning_summary_text.delta", { @@ -1009,7 +1009,7 @@ export function encodeStream( break; } case "thinking_end": { - if (!state.open || state.open.kind !== "reasoning") break; + if (state.open?.kind !== "reasoning") break; const cur: OpenReasoning = state.open; const text = ev.content ?? cur.reasoningText; cur.reasoningText = text; @@ -1034,7 +1034,7 @@ export function encodeStream( break; } case "toolcall_delta": { - if (!state.open || state.open.kind !== "function_call") break; + if (state.open?.kind !== "function_call") break; const cur: OpenFunctionCall = state.open; cur.argsText += ev.delta; if (cur.customWireName) { @@ -1053,7 +1053,7 @@ export function encodeStream( break; } case "toolcall_end": { - if (!state.open || state.open.kind !== "function_call") break; + if (state.open?.kind !== "function_call") break; const cur: OpenFunctionCall = state.open; // Promote possibly-late info from the canonical ToolCall. const tc = ev.toolCall; diff --git a/packages/ai/test/anthropic-stream-envelope.test.ts b/packages/ai/test/anthropic-stream-envelope.test.ts index c01f4f325..f082044fb 100644 --- a/packages/ai/test/anthropic-stream-envelope.test.ts +++ b/packages/ai/test/anthropic-stream-envelope.test.ts @@ -428,7 +428,7 @@ describe("anthropic stream envelope handling", () => { const toolCall = result.content[0]; expect(toolCall?.type).toBe("toolCall"); - if (!toolCall || toolCall.type !== "toolCall") { + if (toolCall?.type !== "toolCall") { throw new Error("Expected toolCall content in terminal error payload"); } expect("partialJson" in toolCall).toBe(false); diff --git a/packages/ai/test/auth-gateway-openai-chat.test.ts b/packages/ai/test/auth-gateway-openai-chat.test.ts index 29a50d0bd..4db5db89f 100644 --- a/packages/ai/test/auth-gateway-openai-chat.test.ts +++ b/packages/ai/test/auth-gateway-openai-chat.test.ts @@ -167,7 +167,7 @@ describe("auth-gateway openai-chat: parseRequest", () => { ], }); const tool = parsed.context.messages.find(m => m.role === "toolResult"); - if (!tool || tool.role !== "toolResult") throw new Error("expected toolResult"); + if (tool?.role !== "toolResult") throw new Error("expected toolResult"); expect(tool.toolName).toBe("submit_move"); }); @@ -184,7 +184,7 @@ describe("auth-gateway openai-chat: parseRequest", () => { ], }); const tool = parsed.context.messages.find(m => m.role === "toolResult"); - if (!tool || tool.role !== "toolResult") throw new Error("expected toolResult"); + if (tool?.role !== "toolResult") throw new Error("expected toolResult"); expect(tool.toolName).toBe("submit_move"); }); @@ -198,7 +198,7 @@ describe("auth-gateway openai-chat: parseRequest", () => { ], }); const tool = parsed.context.messages.find(m => m.role === "toolResult"); - if (!tool || tool.role !== "toolResult") throw new Error("expected toolResult"); + if (tool?.role !== "toolResult") throw new Error("expected toolResult"); expect(tool.toolName).toBe(""); }); }); diff --git a/packages/ai/test/auth-storage-api-key-login.test.ts b/packages/ai/test/auth-storage-api-key-login.test.ts index 16be149b6..df2c6a244 100644 --- a/packages/ai/test/auth-storage-api-key-login.test.ts +++ b/packages/ai/test/auth-storage-api-key-login.test.ts @@ -70,7 +70,7 @@ describe("AuthStorage api-key login replacement", () => { expect(credentials).toHaveLength(1); const [stored] = credentials; expect(stored?.credential.type).toBe("api_key"); - if (!stored || stored.credential.type !== "api_key") { + if (stored?.credential.type !== "api_key") { throw new Error("expected stored api-key credential"); } expect(stored.credential.key).toBe("same-kagi-key"); @@ -96,7 +96,7 @@ describe("AuthStorage api-key login replacement", () => { expect(credentials).toHaveLength(1); const [stored] = credentials; expect(stored?.credential.type).toBe("api_key"); - if (!stored || stored.credential.type !== "api_key") { + if (stored?.credential.type !== "api_key") { throw new Error("expected stored api-key credential"); } expect(stored.credential.key).toBe("same-ollama-cloud-key"); @@ -122,7 +122,7 @@ describe("AuthStorage api-key login replacement", () => { expect(credentials).toHaveLength(1); const [stored] = credentials; expect(stored?.credential.type).toBe("api_key"); - if (!stored || stored.credential.type !== "api_key") { + if (stored?.credential.type !== "api_key") { throw new Error("expected stored api-key credential"); } expect(stored.credential.key).toBe("same-deepseek-key"); diff --git a/packages/ai/test/auth-storage-email-dedupe.test.ts b/packages/ai/test/auth-storage-email-dedupe.test.ts index 434d703aa..e0ae13523 100644 --- a/packages/ai/test/auth-storage-email-dedupe.test.ts +++ b/packages/ai/test/auth-storage-email-dedupe.test.ts @@ -151,7 +151,7 @@ describe("AuthStorage openai-codex email dedupe", () => { expect(credentials).toHaveLength(1); const [remaining] = credentials; expect(remaining?.credential.type).toBe("oauth"); - if (!remaining || remaining.credential.type !== "oauth") throw new Error("expected oauth credential"); + if (remaining?.credential.type !== "oauth") throw new Error("expected oauth credential"); expect(remaining.credential.accountId).toBe("account-b"); expect(remaining.credential.email).toBe("shared.user@example.com"); }); @@ -168,7 +168,7 @@ describe("AuthStorage openai-codex email dedupe", () => { expect(credentials).toHaveLength(1); const [remaining] = credentials; expect(remaining?.credential.type).toBe("oauth"); - if (!remaining || remaining.credential.type !== "oauth") throw new Error("expected oauth credential"); + if (remaining?.credential.type !== "oauth") throw new Error("expected oauth credential"); expect(remaining.credential.accountId).toBe("account-b"); }); @@ -207,7 +207,7 @@ describe("AuthStorage openai-codex email dedupe", () => { expect(credentials).toHaveLength(1); const [remaining] = credentials; expect(remaining?.credential.type).toBe("oauth"); - if (!remaining || remaining.credential.type !== "oauth") throw new Error("expected oauth credential"); + if (remaining?.credential.type !== "oauth") throw new Error("expected oauth credential"); expect(remaining.credential.accountId).toBe("account-b"); expect(remaining.credential.email).toBe("shared.user@example.com"); expect(readDisabledCauses(dbPath, "openai-codex")).toEqual([]); @@ -300,7 +300,7 @@ describe("AuthStorage openai-codex email dedupe", () => { expect(credentials).toHaveLength(1); const [remaining] = credentials; expect(remaining?.credential.type).toBe("oauth"); - if (!remaining || remaining.credential.type !== "oauth") throw new Error("expected oauth credential"); + if (remaining?.credential.type !== "oauth") throw new Error("expected oauth credential"); expect(remaining.credential.accountId).toBe("account-b"); }); @@ -319,7 +319,7 @@ describe("AuthStorage openai-codex email dedupe", () => { expect(credentials).toHaveLength(1); const [remaining] = credentials; expect(remaining?.credential.type).toBe("oauth"); - if (!remaining || remaining.credential.type !== "oauth") throw new Error("expected oauth credential"); + if (remaining?.credential.type !== "oauth") throw new Error("expected oauth credential"); expect(remaining.credential.accountId).toBe("account-b"); expect(remaining.credential.email).toBe("shared.user@example.com"); }); @@ -350,7 +350,7 @@ describe("AuthStorage openai-codex email dedupe", () => { expect(credentials).toHaveLength(1); const [remaining] = credentials; expect(remaining?.credential.type).toBe("oauth"); - if (!remaining || remaining.credential.type !== "oauth") throw new Error("expected oauth credential"); + if (remaining?.credential.type !== "oauth") throw new Error("expected oauth credential"); expect(remaining.credential.accountId).toBe("org-b"); expect(remaining.credential.email).toBe("shared.user@example.com"); }); diff --git a/packages/ai/test/cursor-exec-handlers.test.ts b/packages/ai/test/cursor-exec-handlers.test.ts index afd2c9787..75d0ad2a2 100644 --- a/packages/ai/test/cursor-exec-handlers.test.ts +++ b/packages/ai/test/cursor-exec-handlers.test.ts @@ -142,7 +142,7 @@ describe("Cursor request action encoding", () => { expect(userMessage?.selectedContext?.selectedImages).toHaveLength(1); const selectedImage = userMessage?.selectedContext?.selectedImages[0]; expect(selectedImage?.mimeType).toBe("image/png"); - if (!selectedImage || selectedImage.dataOrBlobId.case !== "data") { + if (selectedImage?.dataOrBlobId.case !== "data") { throw new Error("Expected Cursor selected image data"); } expect(Array.from(selectedImage.dataOrBlobId.value)).toEqual(Array.from(Buffer.from(imageData, "base64"))); diff --git a/packages/ai/test/image-tool-result.test.ts b/packages/ai/test/image-tool-result.test.ts index 47fdb7c0e..2e25e23ba 100644 --- a/packages/ai/test/image-tool-result.test.ts +++ b/packages/ai/test/image-tool-result.test.ts @@ -63,7 +63,7 @@ async function handleToolWithImageResult(model: Model, o // Find the tool call const toolCall = firstResponse.content.find(b => b.type === "toolCall"); expect(toolCall).toBeTruthy(); - if (!toolCall || toolCall.type !== "toolCall") { + if (toolCall?.type !== "toolCall") { throw new Error("Expected tool call"); } expect(toolCall.name).toBe("get_circle"); @@ -152,7 +152,7 @@ async function handleToolWithTextAndImageResult(model: Model b.type === "toolCall"); expect(toolCall).toBeTruthy(); - if (!toolCall || toolCall.type !== "toolCall") { + if (toolCall?.type !== "toolCall") { throw new Error("Expected tool call"); } expect(toolCall.name).toBe("get_circle_with_description"); diff --git a/packages/ai/test/openai-completions-compat.test.ts b/packages/ai/test/openai-completions-compat.test.ts index c05281f37..9eedf15a0 100644 --- a/packages/ai/test/openai-completions-compat.test.ts +++ b/packages/ai/test/openai-completions-compat.test.ts @@ -121,7 +121,7 @@ describe("openai-completions compatibility", () => { const messages = convertMessages(model, { messages: [assistantMessage] }, compat); const assistant = messages.find(message => message.role === "assistant"); expect(assistant).toBeDefined(); - if (!assistant || assistant.role !== "assistant") { + if (assistant?.role !== "assistant") { throw new Error("assistant message missing"); } expect(typeof assistant.content).toBe("string"); diff --git a/packages/coding-agent/src/eval/js/shared/rewrite-imports.ts b/packages/coding-agent/src/eval/js/shared/rewrite-imports.ts index 73a8703a4..b513d957e 100644 --- a/packages/coding-agent/src/eval/js/shared/rewrite-imports.ts +++ b/packages/coding-agent/src/eval/js/shared/rewrite-imports.ts @@ -178,8 +178,7 @@ export function rewriteImports(code: string): string { if (node.type !== "CallExpression") return; const call = node as unknown as { callee?: { type?: string; start?: number; end?: number } }; const callee = call.callee; - if (!callee || callee.type !== "Import" || typeof callee.start !== "number" || typeof callee.end !== "number") - return; + if (callee?.type !== "Import" || typeof callee.start !== "number" || typeof callee.end !== "number") return; edits.push({ start: callee.start, end: callee.end, text: "__omp_import__" }); }); @@ -252,12 +251,7 @@ export function rewriteDynamicImports(code: string, callee = "__omp_import__"): if (node.type !== "CallExpression") return; const call = node as unknown as { callee?: { type?: string; start?: number; end?: number } }; const callCallee = call.callee; - if ( - !callCallee || - callCallee.type !== "Import" || - typeof callCallee.start !== "number" || - typeof callCallee.end !== "number" - ) { + if (callCallee?.type !== "Import" || typeof callCallee.start !== "number" || typeof callCallee.end !== "number") { return; } edits.push({ start: callCallee.start, end: callCallee.end, text: callee }); diff --git a/packages/coding-agent/src/lsp/render.ts b/packages/coding-agent/src/lsp/render.ts index 252e9dcc9..e49e356f3 100644 --- a/packages/coding-agent/src/lsp/render.ts +++ b/packages/coding-agent/src/lsp/render.ts @@ -103,7 +103,7 @@ export function renderResult( args?: LspParams, ): Component { const content = result.content?.[0]; - if (!content || content.type !== "text" || !("text" in content) || !content.text) { + if (content?.type !== "text" || !("text" in content) || !content.text) { const icon = formatStatusIcon("warning", theme, options.spinnerFrame); const header = `${icon} LSP`; return new Text([header, theme.fg("dim", "No result")].join("\n"), 0, 0); diff --git a/packages/coding-agent/src/mcp/oauth-flow.ts b/packages/coding-agent/src/mcp/oauth-flow.ts index 4de143cbc..efcef86a0 100644 --- a/packages/coding-agent/src/mcp/oauth-flow.ts +++ b/packages/coding-agent/src/mcp/oauth-flow.ts @@ -42,7 +42,7 @@ function getUriPort(uri: URL): number { function validateRedirectConfig(config: MCPOAuthConfig, redirectUri: string | undefined): void { const parsed = parseRedirectUri(redirectUri); - if (!parsed || parsed.protocol !== "https:" || !isLoopbackHostname(parsed.hostname)) { + if (parsed?.protocol !== "https:" || !isLoopbackHostname(parsed.hostname)) { return; } @@ -63,7 +63,7 @@ function resolveCallbackPort(callbackPort: number | undefined, redirectUri: stri if (callbackPort !== undefined) return callbackPort; const parsed = parseRedirectUri(redirectUri); - if (!parsed || parsed.protocol !== "http:" || !isLoopbackHostname(parsed.hostname)) { + if (parsed?.protocol !== "http:" || !isLoopbackHostname(parsed.hostname)) { return DEFAULT_PORT; } diff --git a/packages/coding-agent/src/modes/acp/acp-agent.ts b/packages/coding-agent/src/modes/acp/acp-agent.ts index 7d3c8ec4c..1eb3b230f 100644 --- a/packages/coding-agent/src/modes/acp/acp-agent.ts +++ b/packages/coding-agent/src/modes/acp/acp-agent.ts @@ -266,7 +266,7 @@ async function elicitFromAcpClient( finish(undefined); }); const response = await promise; - if (!response || response.action !== "accept" || !response.content) { + if (response?.action !== "accept" || !response.content) { return undefined; } return response.content.value; diff --git a/packages/coding-agent/src/modes/components/agent-dashboard.ts b/packages/coding-agent/src/modes/components/agent-dashboard.ts index 62b2b3e7d..e4336dc80 100644 --- a/packages/coding-agent/src/modes/components/agent-dashboard.ts +++ b/packages/coding-agent/src/modes/components/agent-dashboard.ts @@ -121,7 +121,7 @@ function matchAgent(agent: DashboardAgent, query: string): boolean { function extractAssistantText(messages: AgentMessage[]): string | null { for (let i = messages.length - 1; i >= 0; i--) { const message = messages[i]; - if (!message || message.role !== "assistant") continue; + if (message?.role !== "assistant") continue; const blocks = message.content; if (!Array.isArray(blocks)) continue; const text = blocks diff --git a/packages/coding-agent/src/modes/components/diff.ts b/packages/coding-agent/src/modes/components/diff.ts index 777b013aa..ee69729c8 100644 --- a/packages/coding-agent/src/modes/components/diff.ts +++ b/packages/coding-agent/src/modes/components/diff.ts @@ -151,7 +151,7 @@ export function renderDiff(diffText: string, options: RenderDiffOptions = {}): s const removedLines: { lineNum: string; content: string }[] = []; while (i < lines.length) { const p = parseDiffLine(lines[i]); - if (!p || p.prefix !== "-") break; + if (p?.prefix !== "-") break; removedLines.push({ lineNum: p.lineNum, content: p.content }); i++; } @@ -159,7 +159,7 @@ export function renderDiff(diffText: string, options: RenderDiffOptions = {}): s const addedLines: { lineNum: string; content: string }[] = []; while (i < lines.length) { const p = parseDiffLine(lines[i]); - if (!p || p.prefix !== "+") break; + if (p?.prefix !== "+") break; addedLines.push({ lineNum: p.lineNum, content: p.content }); i++; } diff --git a/packages/coding-agent/src/modes/components/tips.txt b/packages/coding-agent/src/modes/components/tips.txt index c5a5bd1c3..1a54c1d2d 100644 --- a/packages/coding-agent/src/modes/components/tips.txt +++ b/packages/coding-agent/src/modes/components/tips.txt @@ -8,4 +8,5 @@ Next time you see spaghet try: "omp, create a TTSR rule that will prevent this p Did you know? Each kitty/tmux split keeps its own session — `omp -c` resumes the right one Drop the word `ultrathink` in your message for harder multi-step reasoning — watch it glow rainbow as you type Say `orchestrate` in your message to drive a multi-phase task with parallel subagents — watch it glow as you type -Log in to several accounts of the same provider — `/login` again — and omp load-balances across them automatically \ No newline at end of file +Log in to several accounts of the same provider — `/login` again — and omp load-balances across them automatically +Run `omp auth-broker serve` once and every machine pulls live tokens over the wire — refresh keys never leave the host; `omp auth-gateway` fronts it as a drop-in proxy any OpenAI-compatible client can hit \ No newline at end of file diff --git a/packages/coding-agent/src/session/agent-session.ts b/packages/coding-agent/src/session/agent-session.ts index 40eb07214..e29270d48 100644 --- a/packages/coding-agent/src/session/agent-session.ts +++ b/packages/coding-agent/src/session/agent-session.ts @@ -6227,7 +6227,7 @@ export class AgentSession { #closeCodexProviderSessionsForHistoryRewrite(): void { const currentModel = this.model; - if (!currentModel || currentModel.api !== "openai-codex-responses") return; + if (currentModel?.api !== "openai-codex-responses") return; this.#closeProviderSessionsForModelSwitch(currentModel, currentModel); } @@ -8366,7 +8366,7 @@ export class AgentSession { const previousSessionFile = this.sessionFile; const selectedEntry = this.sessionManager.getEntry(entryId); - if (!selectedEntry || selectedEntry.type !== "message" || selectedEntry.message.role !== "user") { + if (selectedEntry?.type !== "message" || selectedEntry.message.role !== "user") { throw new Error("Invalid entry ID for branching"); } diff --git a/packages/coding-agent/src/tools/browser/tab-worker.ts b/packages/coding-agent/src/tools/browser/tab-worker.ts index 9cc0811e4..308cd6e27 100644 --- a/packages/coding-agent/src/tools/browser/tab-worker.ts +++ b/packages/coding-agent/src/tools/browser/tab-worker.ts @@ -917,7 +917,7 @@ export class WorkerCore { dispatchEvent: (event: unknown) => boolean; } const select = el as unknown as SelectLike; - if (!select || select.tagName !== "SELECT") throw new Error("tab.select() requires a element"); const EventCtor = ( globalThis as unknown as { Event: new (type: string, init?: { bubbles: boolean }) => unknown } ).Event; diff --git a/packages/coding-agent/test/acp-agent.test.ts b/packages/coding-agent/test/acp-agent.test.ts index 9c668ea5f..89e8df91c 100644 --- a/packages/coding-agent/test/acp-agent.test.ts +++ b/packages/coding-agent/test/acp-agent.test.ts @@ -1893,12 +1893,9 @@ describe("ACP agent", () => { // only `"sessionId" in call` picks the session-scoped variant — and // loop-style narrows don't propagate to the assertions below. const [first, second, third] = calls; - if (!first || first.mode !== "form" || !("sessionId" in first)) - throw new Error("first call missing sessionId"); - if (!second || second.mode !== "form" || !("sessionId" in second)) - throw new Error("second call missing sessionId"); - if (!third || third.mode !== "form" || !("sessionId" in third)) - throw new Error("third call missing sessionId"); + if (first?.mode !== "form" || !("sessionId" in first)) throw new Error("first call missing sessionId"); + if (second?.mode !== "form" || !("sessionId" in second)) throw new Error("second call missing sessionId"); + if (third?.mode !== "form" || !("sessionId" in third)) throw new Error("third call missing sessionId"); expect(first.sessionId).toBe("session-before-switch"); expect(second.sessionId).toBe("session-after-switch"); expect(third.sessionId).toBe("session-after-switch"); diff --git a/packages/coding-agent/test/agent-session-before-agent-start-attribution.test.ts b/packages/coding-agent/test/agent-session-before-agent-start-attribution.test.ts index adfd26b25..1202902c4 100644 --- a/packages/coding-agent/test/agent-session-before-agent-start-attribution.test.ts +++ b/packages/coding-agent/test/agent-session-before-agent-start-attribution.test.ts @@ -106,7 +106,7 @@ describe("AgentSession before_agent_start attribution fallback", () => { expect(emitBeforeAgentStart).toHaveBeenCalledTimes(1); const injectedMessage = findBeforeStartInjection(session.messages); expect(injectedMessage).toBeDefined(); - if (!injectedMessage || injectedMessage.role !== "custom") { + if (injectedMessage?.role !== "custom") { throw new Error("Expected injected custom message in session state"); } @@ -128,7 +128,7 @@ describe("AgentSession before_agent_start attribution fallback", () => { expect(emitBeforeAgentStart).toHaveBeenCalledTimes(1); const injectedMessage = findBeforeStartInjection(session.messages); expect(injectedMessage).toBeDefined(); - if (!injectedMessage || injectedMessage.role !== "custom") { + if (injectedMessage?.role !== "custom") { throw new Error("Expected injected custom message in session state"); } @@ -152,7 +152,7 @@ describe("AgentSession before_agent_start attribution fallback", () => { const promptMessage = findPromptMessage(session.messages, promptText); expect(promptMessage).toBeDefined(); expect(promptMessage?.role).toBe("user"); - if (!promptMessage || promptMessage.role !== "user") { + if (promptMessage?.role !== "user") { throw new Error("Expected delegated prompt to remain a user-role message"); } expect(promptMessage.attribution).toBe("agent"); diff --git a/packages/coding-agent/test/agent-session-manual-retry.test.ts b/packages/coding-agent/test/agent-session-manual-retry.test.ts index 9d922cd51..0fa4809a8 100644 --- a/packages/coding-agent/test/agent-session-manual-retry.test.ts +++ b/packages/coding-agent/test/agent-session-manual-retry.test.ts @@ -12,7 +12,7 @@ import { TempDir } from "@oh-my-pi/pi-utils"; function lastAgentMessage(session: AgentSession): AssistantMessage { const message = session.agent.state.messages.at(-1); - if (!message || message.role !== "assistant") { + if (message?.role !== "assistant") { throw new Error("Expected trailing assistant message"); } return message as AssistantMessage; diff --git a/packages/coding-agent/test/agent-session-openai-responses-replay.test.ts b/packages/coding-agent/test/agent-session-openai-responses-replay.test.ts index 3e6e4ecbe..e1720ede7 100644 --- a/packages/coding-agent/test/agent-session-openai-responses-replay.test.ts +++ b/packages/coding-agent/test/agent-session-openai-responses-replay.test.ts @@ -152,7 +152,7 @@ function findRuntimeAssistant(session: AgentSession, text: string): AssistantMes const message = session.messages.find( candidate => candidate.role === "assistant" && getTextContent(candidate) === text, ); - if (!message || message.role !== "assistant") { + if (message?.role !== "assistant") { throw new Error(`Expected runtime assistant message with text: ${text}`); } return message; @@ -164,19 +164,19 @@ function expectAssistantReplayMetadataSanitized(message: AssistantMessage): void expect(message.providerPayload).toBeUndefined(); const thinkingBlock = message.content.find(block => block.type === "thinking"); - if (!thinkingBlock || thinkingBlock.type !== "thinking") { + if (thinkingBlock?.type !== "thinking") { throw new Error("Expected assistant thinking block"); } expect(thinkingBlock.thinkingSignature).toBeUndefined(); const textBlock = message.content.find(block => block.type === "text"); - if (!textBlock || textBlock.type !== "text") { + if (textBlock?.type !== "text") { throw new Error("Expected assistant text block"); } expect(textBlock.textSignature).toBe("text_sig_preserved"); const toolCallBlock = message.content.find(block => block.type === "toolCall"); - if (!toolCallBlock || toolCallBlock.type !== "toolCall") { + if (toolCallBlock?.type !== "toolCall") { throw new Error("Expected assistant tool call block"); } expect(toolCallBlock).toMatchObject({ @@ -299,7 +299,7 @@ describe("AgentSession OpenAI Responses replay boundaries", () => { const runtimeUser = session.messages.find( message => message.role === "user" && getTextContent(message) === "Preserved summary", ); - if (!runtimeUser || runtimeUser.role !== "user") { + if (runtimeUser?.role !== "user") { throw new Error("Expected runtime user message"); } expect(runtimeUser.providerPayload).toEqual(preservedUserPayload); @@ -458,7 +458,7 @@ describe("AgentSession OpenAI Responses replay boundaries", () => { const customEntry = snapshot.fileEntries.find( entry => entry.type === "custom_message" && entry.customType === "proxy-details", ); - if (!customEntry || customEntry.type !== "custom_message") { + if (customEntry?.type !== "custom_message") { throw new Error("Expected captured custom message entry"); } expect(customEntry.details).toEqual({ ok: true, nested: { value: "preserved" } }); diff --git a/packages/coding-agent/test/agent-session-retry-cap.test.ts b/packages/coding-agent/test/agent-session-retry-cap.test.ts index 4ddcc5c9e..8b313b961 100644 --- a/packages/coding-agent/test/agent-session-retry-cap.test.ts +++ b/packages/coding-agent/test/agent-session-retry-cap.test.ts @@ -16,7 +16,7 @@ type AutoRetryStartEvent = Extract { const messages = await generateFileMentionMessages(["httpserap"], cwd); expect(messages).toHaveLength(1); const message = messages[0]; - if (!message || message.role !== "fileMention") { + if (message?.role !== "fileMention") { throw new Error("expected file mention message"); } expect(message.files).toHaveLength(1); @@ -44,7 +44,7 @@ describe("generateFileMentionMessages path resolution", () => { const messages = await generateFileMentionMessages(["docs/rea"], cwd); expect(messages).toHaveLength(1); const message = messages[0]; - if (!message || message.role !== "fileMention") { + if (message?.role !== "fileMention") { throw new Error("expected file mention message"); } expect(message.files[0]?.path).toBe("docs/readme.md"); @@ -59,7 +59,7 @@ describe("generateFileMentionMessages path resolution", () => { const messages = await generateFileMentionMessages(["httpserap"], cwd); expect(messages).toHaveLength(1); const message = messages[0]; - if (!message || message.role !== "fileMention") { + if (message?.role !== "fileMention") { throw new Error("expected file mention message"); } expect(message.files[0]?.path).toBe("http_server_api_tests"); diff --git a/packages/coding-agent/test/rpc-host-tools.test.ts b/packages/coding-agent/test/rpc-host-tools.test.ts index 5d4e2ed03..ccd5fca7b 100644 --- a/packages/coding-agent/test/rpc-host-tools.test.ts +++ b/packages/coding-agent/test/rpc-host-tools.test.ts @@ -53,7 +53,7 @@ describe("RpcHostToolBridge", () => { expect(frames).toHaveLength(1); const request = frames[0]; - if (!request || request.type !== "host_tool_call") { + if (request?.type !== "host_tool_call") { throw new Error("Expected host_tool_call frame"); } @@ -100,7 +100,7 @@ describe("RpcHostToolBridge", () => { const controller = new AbortController(); const execution = tool.execute("toolu_2", {}, controller.signal); const request = frames[0]; - if (!request || request.type !== "host_tool_call") { + if (request?.type !== "host_tool_call") { throw new Error("Expected host_tool_call frame"); } diff --git a/packages/coding-agent/test/rpc-host-uris.test.ts b/packages/coding-agent/test/rpc-host-uris.test.ts index a762c58b6..16df49f95 100644 --- a/packages/coding-agent/test/rpc-host-uris.test.ts +++ b/packages/coding-agent/test/rpc-host-uris.test.ts @@ -33,7 +33,7 @@ describe("RpcHostUriBridge", () => { const pending = bridge.requestRead("db", parseInternalUrl("db://users/42")); expect(out.frames).toHaveLength(1); const request = out.frames[0]; - if (!request || request.type !== "host_uri_request") { + if (request?.type !== "host_uri_request") { throw new Error("Expected host_uri_request frame"); } expect(request.operation).toBe("read"); @@ -71,7 +71,7 @@ describe("RpcHostUriBridge", () => { const pending = bridge.requestWrite("db", url, "new content"); expect(out.frames).toHaveLength(1); const request = out.frames[0]; - if (!request || request.type !== "host_uri_request") { + if (request?.type !== "host_uri_request") { throw new Error("Expected host_uri_request frame"); } expect(request.operation).toBe("write"); @@ -90,7 +90,7 @@ describe("RpcHostUriBridge", () => { const url = parseInternalUrl("db://users/42"); const pending = bridge.requestRead("db", url); const request = out.frames[0]; - if (!request || request.type !== "host_uri_request") { + if (request?.type !== "host_uri_request") { throw new Error("Expected host_uri_request frame"); } bridge.handleResult({ diff --git a/packages/coding-agent/test/session-manager-internal-details.test.ts b/packages/coding-agent/test/session-manager-internal-details.test.ts index 6c76498d1..b963979c9 100644 --- a/packages/coding-agent/test/session-manager-internal-details.test.ts +++ b/packages/coding-agent/test/session-manager-internal-details.test.ts @@ -20,7 +20,7 @@ const SKILL_TYPE = "skill-prompt"; function readPersistedCustomMessageEntry(session: SessionManager, id: string): CustomMessageEntry { const branch = session.getBranch(); const entry = branch.find(e => e.id === id); - if (!entry || entry.type !== "custom_message") { + if (entry?.type !== "custom_message") { throw new Error(`Expected custom_message entry with id ${id}, got ${entry?.type ?? "none"}`); } return entry as CustomMessageEntry; diff --git a/packages/coding-agent/test/session-manager/signature-persistence.test.ts b/packages/coding-agent/test/session-manager/signature-persistence.test.ts index 01f556493..05070225d 100644 --- a/packages/coding-agent/test/session-manager/signature-persistence.test.ts +++ b/packages/coding-agent/test/session-manager/signature-persistence.test.ts @@ -113,7 +113,7 @@ describe("SessionManager signature persistence", () => { const reloadedUserEntry = reloaded .getEntries() .find(entry => entry.type === "message" && entry.message.role === "user"); - if (!reloadedUserEntry || reloadedUserEntry.type !== "message" || reloadedUserEntry.message.role !== "user") { + if (reloadedUserEntry?.type !== "message" || reloadedUserEntry.message.role !== "user") { throw new Error("Expected user message"); } diff --git a/packages/coding-agent/test/streaming-render-debug.ts b/packages/coding-agent/test/streaming-render-debug.ts index 04713cfa7..222f28787 100644 --- a/packages/coding-agent/test/streaming-render-debug.ts +++ b/packages/coding-agent/test/streaming-render-debug.ts @@ -24,7 +24,7 @@ async function main() { const thinkingContent = fixtureMessage.content.find(c => c.type === "thinking"); const textContent = fixtureMessage.content.find(c => c.type === "text"); - if (!thinkingContent || thinkingContent.type !== "thinking") { + if (thinkingContent?.type !== "thinking") { console.error("No thinking content in fixture"); process.exit(1); } diff --git a/packages/coding-agent/test/tools/eval-display-text.test.ts b/packages/coding-agent/test/tools/eval-display-text.test.ts index f88f995ec..a8e74f22c 100644 --- a/packages/coding-agent/test/tools/eval-display-text.test.ts +++ b/packages/coding-agent/test/tools/eval-display-text.test.ts @@ -135,7 +135,7 @@ describe("EvalTool display() text surfacing", () => { const image = result.content.find(c => c.type === "image"); expect(image).toBeDefined(); - if (!image || image.type !== "image") throw new Error("Expected image content"); + if (image?.type !== "image") throw new Error("Expected image content"); expect(image.data).not.toBe(base64); const { width, height } = await new Bun.Image(Buffer.from(image.data, "base64")).metadata(); diff --git a/packages/coding-agent/test/tools/todo-write.test.ts b/packages/coding-agent/test/tools/todo-write.test.ts index 655162bc7..183056f6b 100644 --- a/packages/coding-agent/test/tools/todo-write.test.ts +++ b/packages/coding-agent/test/tools/todo-write.test.ts @@ -40,7 +40,7 @@ describe("TodoWriteTool auto-start behavior", () => { const tasks = result.details?.phases[0]?.tasks ?? []; expect(tasks.map(task => task.status)).toEqual(["in_progress", "pending"]); const summary = result.content.find(part => part.type === "text"); - if (!summary || summary.type !== "text") throw new Error("Expected text summary from todo_write"); + if (summary?.type !== "text") throw new Error("Expected text summary from todo_write"); expect(summary.text).toContain("Remaining items (2):"); expect(summary.text).toContain("status [in_progress] (Execution)"); expect(summary.text).toContain("diagnostics [pending] (Execution)"); @@ -62,13 +62,13 @@ describe("TodoWriteTool auto-start behavior", () => { const tasks = result.details?.phases[0]?.tasks ?? []; expect(tasks.map(task => task.status)).toEqual(["completed", "in_progress"]); const summary = result.content.find(part => part.type === "text"); - if (!summary || summary.type !== "text") throw new Error("Expected text summary from todo_write"); + if (summary?.type !== "text") throw new Error("Expected text summary from todo_write"); expect(summary.text).toContain("Remaining items (1):"); expect(summary.text).toContain("diagnostics [in_progress] (Execution)"); const completedResult = await tool.execute("call-3", { ops: [{ op: "done", task: "diagnostics" }] }); const completedSummary = completedResult.content.find(part => part.type === "text"); - if (!completedSummary || completedSummary.type !== "text") { + if (completedSummary?.type !== "text") { throw new Error("Expected text summary from todo_write"); } expect(completedSummary.text).toContain("Remaining items: none."); @@ -189,7 +189,7 @@ describe("TodoWriteTool ops operations", () => { const result = await tool.execute("call-2", { ops: [{ op: "rm" }] }); expect(result.details?.phases[0]?.tasks).toEqual([]); const summary = result.content.find(part => part.type === "text"); - if (!summary || summary.type !== "text") throw new Error("Expected text summary"); + if (summary?.type !== "text") throw new Error("Expected text summary"); expect(summary.text).toContain("Todo list cleared."); }); diff --git a/packages/stats/src/aggregator.ts b/packages/stats/src/aggregator.ts index a58125cce..97fba24df 100644 --- a/packages/stats/src/aggregator.ts +++ b/packages/stats/src/aggregator.ts @@ -422,7 +422,7 @@ export async function getRequestDetails(id: number): Promise