refactor(tools): narrow optional values

Avoid non-null assertions in tool and doctor code by preserving narrowed locals through each use site.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
YeonGyu-Kim
2026-05-15 16:31:13 +09:00
parent d92e78c956
commit 0a3d1875f7
5 changed files with 27 additions and 15 deletions
+6 -2
View File
@@ -6,7 +6,11 @@ import type { DependencyInfo } from "../types"
import { spawnWithTimeout } from "../spawn-with-timeout" import { spawnWithTimeout } from "../spawn-with-timeout"
import { getCachedBinaryPath } from "../../../hooks/comment-checker/downloader" import { getCachedBinaryPath } from "../../../hooks/comment-checker/downloader"
async function checkBinaryExists(binary: string): Promise<{ exists: boolean; path: string | null }> { type BinaryCheck =
| { exists: true; path: string }
| { exists: false; path: null }
async function checkBinaryExists(binary: string): Promise<BinaryCheck> {
try { try {
const path = Bun.which(binary) const path = Bun.which(binary)
if (path) { if (path) {
@@ -44,7 +48,7 @@ export async function checkAstGrepCli(): Promise<DependencyInfo> {
} }
} }
const version = await getBinaryVersion(binary.path!) const version = await getBinaryVersion(binary.path)
return { return {
name: "AST-Grep CLI", name: "AST-Grep CLI",
@@ -15,10 +15,6 @@ export function createBackgroundCancel(manager: BackgroundManager, _client: Back
try { try {
const cancelAll = args.all === true const cancelAll = args.all === true
if (!cancelAll && !args.taskId) {
return `[ERROR] Invalid arguments: Either provide a taskId or set all=true to cancel all running tasks.`
}
if (cancelAll) { if (cancelAll) {
const tasks = manager.getAllDescendantTasks(toolContext.sessionID) const tasks = manager.getAllDescendantTasks(toolContext.sessionID)
const cancellableTasks = tasks.filter((t: { status: string }) => t.status === "running" || t.status === "pending") const cancellableTasks = tasks.filter((t: { status: string }) => t.status === "running" || t.status === "pending")
@@ -74,9 +70,14 @@ ${tableRows}
${resumeSection}` ${resumeSection}`
} }
const task = manager.getTask(args.taskId!) const taskId = args.taskId
if (!taskId) {
return `[ERROR] Invalid arguments: Either provide a taskId or set all=true to cancel all running tasks.`
}
const task = manager.getTask(taskId)
if (!task) { if (!task) {
return `[ERROR] Task not found: ${args.taskId}` return `[ERROR] Task not found: ${taskId}`
} }
if (task.status !== "running" && task.status !== "pending") { if (task.status !== "running" && task.status !== "pending") {
+3 -2
View File
@@ -13,10 +13,11 @@ export function normalizeArgs(args: LookAtArgsWithAlias): LookAtArgs {
} }
export function validateArgs(args: LookAtArgs): string | null { export function validateArgs(args: LookAtArgs): string | null {
const hasFilePath = Boolean(args.file_path && args.file_path.length > 0) const filePath = args.file_path
const hasFilePath = Boolean(filePath && filePath.length > 0)
const hasImageData = Boolean(args.image_data && args.image_data.length > 0) const hasImageData = Boolean(args.image_data && args.image_data.length > 0)
if (hasFilePath && /^https?:\/\//i.test(args.file_path!)) { if (filePath && /^https?:\/\//i.test(filePath)) {
return "Error: Remote URLs are not supported for file_path. Download the file first or use a local path." return "Error: Remote URLs are not supported for file_path. Download the file first or use a local path."
} }
if (!hasFilePath && !hasImageData) { if (!hasFilePath && !hasImageData) {
+8 -3
View File
@@ -136,22 +136,27 @@ export class LSPClientTransport {
throw new Error(`LSP server already exited (code: ${this.proc?.exitCode})` + (stderr ? `\nstderr: ${stderr}` : "")) throw new Error(`LSP server already exited (code: ${this.proc?.exitCode})` + (stderr ? `\nstderr: ${stderr}` : ""))
} }
let timeoutId: ReturnType<typeof setTimeout> let timeoutId: ReturnType<typeof setTimeout> | undefined
const timeoutPromise = new Promise<never>((_, reject) => { const timeoutPromise = new Promise<never>((_, reject) => {
timeoutId = setTimeout(() => { timeoutId = setTimeout(() => {
const stderr = this.stderrBuffer.slice(-5).join("\n") const stderr = this.stderrBuffer.slice(-5).join("\n")
reject(new Error(`LSP request timeout (method: ${method})` + (stderr ? `\nrecent stderr: ${stderr}` : ""))) reject(new Error(`LSP request timeout (method: ${method})` + (stderr ? `\nrecent stderr: ${stderr}` : "")))
}, this.REQUEST_TIMEOUT) }, this.REQUEST_TIMEOUT)
}) })
const clearRequestTimeout = (): void => {
if (timeoutId !== undefined) {
clearTimeout(timeoutId)
}
}
const requestPromise = this.connection.sendRequest(method, ...args) as Promise<T> const requestPromise = this.connection.sendRequest(method, ...args) as Promise<T>
try { try {
const result = await Promise.race([requestPromise, timeoutPromise]) const result = await Promise.race([requestPromise, timeoutPromise])
clearTimeout(timeoutId!) clearRequestTimeout()
return result return result
} catch (error) { } catch (error) {
clearTimeout(timeoutId!) clearRequestTimeout()
throw error throw error
} }
} }
+3 -2
View File
@@ -22,12 +22,13 @@ export const lsp_symbols: ToolDefinition = tool({
const scope = args.scope ?? "document" const scope = args.scope ?? "document"
if (scope === "workspace") { if (scope === "workspace") {
if (!args.query) { const query = args.query
if (!query) {
return "Error: 'query' is required for workspace scope" return "Error: 'query' is required for workspace scope"
} }
const result = await withLspClient(args.filePath, async (client) => { const result = await withLspClient(args.filePath, async (client) => {
return (await client.workspaceSymbols(args.query!)) as SymbolInfo[] | null return (await client.workspaceSymbols(query)) as SymbolInfo[] | null
}) })
if (!result || result.length === 0) { if (!result || result.length === 0) {