diff options
| author | Kit Langton <[email protected]> | 2026-04-15 23:50:47 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2026-04-16 03:50:47 +0000 |
| commit | 8aa0f9fe9515ba0234ab6a0a58c868068913bb05 (patch) | |
| tree | d079fdd75796492449157256dafe7e309e04da63 /packages | |
| parent | c802695ee9555ccfd8b0a6ae2215f750bccda712 (diff) | |
| download | opencode-8aa0f9fe9515ba0234ab6a0a58c868068913bb05.tar.gz opencode-8aa0f9fe9515ba0234ab6a0a58c868068913bb05.zip | |
feat: enable type-aware no-base-to-string rule, fix 56 violations (#22750)
Diffstat (limited to 'packages')
25 files changed, 83 insertions, 55 deletions
diff --git a/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx index b8f089864..5b4389466 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/black-section.tsx @@ -116,9 +116,9 @@ const createSessionUrl = action(async (workspaceID: string, returnUrl: string) = const setUseBalance = action(async (form: FormData) => { "use server" - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } - const useBalance = form.get("useBalance")?.toString() === "true" + const useBalance = (form.get("useBalance") as string | null) === "true" return json( await withActor(async () => { diff --git a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx index ef54b8409..7da1de238 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/monthly-limit-section.tsx @@ -10,11 +10,11 @@ import { formError, localizeError } from "~/lib/form-error" const setMonthlyLimit = action(async (form: FormData) => { "use server" - const limit = form.get("limit")?.toString() + const limit = form.get("limit") as string | null if (!limit) return { error: formError.limitRequired } const numericLimit = parseInt(limit) if (numericLimit < 0) return { error: formError.monthlyLimitInvalid } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json( await withActor( diff --git a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx index a25963ab0..c9a72c087 100644 --- a/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/billing/reload-section.tsx @@ -12,7 +12,7 @@ import { formError, formErrorReloadAmountMin, formErrorReloadTriggerMin, localiz const reload = action(async (form: FormData) => { "use server" - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json(await withActor(() => Billing.reload(), workspaceID), { revalidate: queryBillingInfo.key, @@ -21,11 +21,11 @@ const reload = action(async (form: FormData) => { const setReload = action(async (form: FormData) => { "use server" - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } - const reloadValue = form.get("reload")?.toString() === "true" - const amountStr = form.get("reloadAmount")?.toString() - const triggerStr = form.get("reloadTrigger")?.toString() + const reloadValue = (form.get("reload") as string | null) === "true" + const amountStr = form.get("reloadAmount") as string | null + const triggerStr = form.get("reloadTrigger") as string | null const reloadAmount = amountStr && amountStr.trim() !== "" ? parseInt(amountStr) : null const reloadTrigger = triggerStr && triggerStr.trim() !== "" ? parseInt(triggerStr) : null @@ -91,8 +91,8 @@ export function ReloadSection() { const info = billingInfo()! setStore("show", true) setStore("reload", true) - setStore("reloadAmount", info.reloadAmount.toString()) - setStore("reloadTrigger", info.reloadTrigger.toString()) + setStore("reloadAmount", String(info.reloadAmount)) + setStore("reloadTrigger", String(info.reloadTrigger)) } function hide() { @@ -152,11 +152,11 @@ export function ReloadSection() { data-component="input" name="reloadAmount" type="number" - min={billingInfo()?.reloadAmountMin.toString()} + min={String(billingInfo()?.reloadAmountMin ?? "")} step="1" value={store.reloadAmount} onInput={(e) => setStore("reloadAmount", e.currentTarget.value)} - placeholder={billingInfo()?.reloadAmount.toString()} + placeholder={String(billingInfo()?.reloadAmount ?? "")} disabled={!store.reload} /> </div> @@ -166,11 +166,11 @@ export function ReloadSection() { data-component="input" name="reloadTrigger" type="number" - min={billingInfo()?.reloadTriggerMin.toString()} + min={String(billingInfo()?.reloadTriggerMin ?? "")} step="1" value={store.reloadTrigger} onInput={(e) => setStore("reloadTrigger", e.currentTarget.value)} - placeholder={billingInfo()?.reloadTrigger.toString()} + placeholder={String(billingInfo()?.reloadTrigger ?? "")} disabled={!store.reload} /> </div> diff --git a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx index 95ff7af2b..d0f812182 100644 --- a/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/go/lite-section.tsx @@ -120,9 +120,9 @@ const createSessionUrl = action(async (workspaceID: string, returnUrl: string) = const setLiteUseBalance = action(async (form: FormData) => { "use server" - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } - const useBalance = form.get("useBalance")?.toString() === "true" + const useBalance = (form.get("useBalance") as string | null) === "true" return json( await withActor(async () => { diff --git a/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx b/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx index 837ab743a..cb273a422 100644 --- a/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/keys/key-section.tsx @@ -12,18 +12,18 @@ import { formError, localizeError } from "~/lib/form-error" const removeKey = action(async (form: FormData) => { "use server" - const id = form.get("id")?.toString() + const id = form.get("id") as string | null if (!id) return { error: formError.idRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json(await withActor(() => Key.remove({ id }), workspaceID), { revalidate: listKeys.key }) }, "key.remove") const createKey = action(async (form: FormData) => { "use server" - const name = form.get("name")?.toString().trim() + const name = (form.get("name") as string | null)?.trim() if (!name) return { error: formError.nameRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json( await withActor( diff --git a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx index 5a440632f..00edb400c 100644 --- a/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/members/member-section.tsx @@ -24,13 +24,13 @@ const listMembers = query(async (workspaceID: string) => { const inviteMember = action(async (form: FormData) => { "use server" - const email = form.get("email")?.toString().trim() + const email = (form.get("email") as string | null)?.trim() if (!email) return { error: formError.emailRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } - const role = form.get("role")?.toString() as (typeof UserRole)[number] + const role = form.get("role") as (typeof UserRole)[number] | null if (!role) return { error: formError.roleRequired } - const limit = form.get("limit")?.toString() + const limit = form.get("limit") as string | null const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null if (monthlyLimit !== null && monthlyLimit < 0) return { error: formError.monthlyLimitInvalid } return json( @@ -47,9 +47,9 @@ const inviteMember = action(async (form: FormData) => { const removeMember = action(async (form: FormData) => { "use server" - const id = form.get("id")?.toString() + const id = form.get("id") as string | null if (!id) return { error: formError.idRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json( await withActor( @@ -66,13 +66,13 @@ const removeMember = action(async (form: FormData) => { const updateMember = action(async (form: FormData) => { "use server" - const id = form.get("id")?.toString() + const id = form.get("id") as string | null if (!id) return { error: formError.idRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } - const role = form.get("role")?.toString() as (typeof UserRole)[number] + const role = form.get("role") as (typeof UserRole)[number] | null if (!role) return { error: formError.roleRequired } - const limit = form.get("limit")?.toString() + const limit = form.get("limit") as string | null const monthlyLimit = limit && limit.trim() !== "" ? parseInt(limit) : null if (monthlyLimit !== null && monthlyLimit < 0) return { error: formError.monthlyLimitInvalid } @@ -118,7 +118,7 @@ function MemberRow(props: { } setStore("editing", true) setStore("selectedRole", props.member.role) - setStore("limit", props.member.monthlyLimit?.toString() ?? "") + setStore("limit", props.member.monthlyLimit != null ? String(props.member.monthlyLimit) : "") } function hide() { diff --git a/packages/console/app/src/routes/workspace/[id]/model-section.tsx b/packages/console/app/src/routes/workspace/[id]/model-section.tsx index bf19f81cd..b9cdf3bc3 100644 --- a/packages/console/app/src/routes/workspace/[id]/model-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/model-section.tsx @@ -67,11 +67,11 @@ const getModelsInfo = query(async (workspaceID: string) => { const updateModel = action(async (form: FormData) => { "use server" - const model = form.get("model")?.toString() + const model = form.get("model") as string | null if (!model) return { error: formError.modelRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } - const enabled = form.get("enabled")?.toString() === "true" + const enabled = (form.get("enabled") as string | null) === "true" return json( withActor(async () => { if (enabled) { @@ -163,7 +163,7 @@ export function ModelSection() { <form action={updateModel} method="post"> <input type="hidden" name="model" value={id} /> <input type="hidden" name="workspaceID" value={params.id} /> - <input type="hidden" name="enabled" value={isEnabled().toString()} /> + <input type="hidden" name="enabled" value={String(isEnabled())} /> <label data-slot="model-toggle-label"> <input type="checkbox" diff --git a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx index fe04bf7c0..acdd89742 100644 --- a/packages/console/app/src/routes/workspace/[id]/provider-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/provider-section.tsx @@ -21,9 +21,9 @@ function maskCredentials(credentials: string) { const removeProvider = action(async (form: FormData) => { "use server" - const provider = form.get("provider")?.toString() + const provider = form.get("provider") as string | null if (!provider) return { error: formError.providerRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json(await withActor(() => Provider.remove({ provider }), workspaceID), { revalidate: listProviders.key, @@ -32,11 +32,11 @@ const removeProvider = action(async (form: FormData) => { const saveProvider = action(async (form: FormData) => { "use server" - const provider = form.get("provider")?.toString() - const credentials = form.get("credentials")?.toString() + const provider = form.get("provider") as string | null + const credentials = form.get("credentials") as string | null if (!provider) return { error: formError.providerRequired } if (!credentials) return { error: formError.apiKeyRequired } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json( await withActor( @@ -59,10 +59,13 @@ function ProviderRow(props: { provider: Provider }) { const params = useParams() const i18n = useI18n() const providers = createAsync(() => listProviders(params.id!)) - const saveSubmission = useSubmission(saveProvider, ([fd]) => fd.get("provider")?.toString() === props.provider.key) + const saveSubmission = useSubmission( + saveProvider, + ([fd]) => (fd.get("provider") as string | null) === props.provider.key, + ) const removeSubmission = useSubmission( removeProvider, - ([fd]) => fd.get("provider")?.toString() === props.provider.key, + ([fd]) => (fd.get("provider") as string | null) === props.provider.key, ) const [store, setStore] = createStore({ editing: false }) diff --git a/packages/console/app/src/routes/workspace/[id]/settings/settings-section.tsx b/packages/console/app/src/routes/workspace/[id]/settings/settings-section.tsx index 5e8331e26..a9950c41e 100644 --- a/packages/console/app/src/routes/workspace/[id]/settings/settings-section.tsx +++ b/packages/console/app/src/routes/workspace/[id]/settings/settings-section.tsx @@ -30,10 +30,10 @@ const getWorkspaceInfo = query(async (workspaceID: string) => { const updateWorkspace = action(async (form: FormData) => { "use server" - const name = form.get("name")?.toString().trim() + const name = (form.get("name") as string | null)?.trim() if (!name) return { error: formError.workspaceNameRequired } if (name.length > 255) return { error: formError.nameTooLong } - const workspaceID = form.get("workspaceID")?.toString() + const workspaceID = form.get("workspaceID") as string | null if (!workspaceID) return { error: formError.workspaceRequired } return json( await withActor( diff --git a/packages/opencode/script/schema.ts b/packages/opencode/script/schema.ts index 4aa27423b..cf63d6743 100755 --- a/packages/opencode/script/schema.ts +++ b/packages/opencode/script/schema.ts @@ -33,7 +33,7 @@ function generate(schema: z.ZodType) { schema.examples = [schema.default] } - schema.description = [schema.description || "", `default: \`${schema.default}\``] + schema.description = [schema.description || "", `default: \`${String(schema.default)}\``] .filter(Boolean) .join("\n\n") .trim() diff --git a/packages/opencode/src/effect/logger.ts b/packages/opencode/src/effect/logger.ts index 97b614fc0..21e0fc43a 100644 --- a/packages/opencode/src/effect/logger.ts +++ b/packages/opencode/src/effect/logger.ts @@ -15,7 +15,9 @@ const clean = (input?: Fields): Fields => Object.fromEntries(Object.entries(input ?? {}).filter((entry) => entry[1] !== undefined && entry[1] !== null)) const text = (input: unknown): string => { + // oxlint-disable-next-line no-base-to-string if (Array.isArray(input)) return input.map((item) => String(item)).join(" ") + // oxlint-disable-next-line no-base-to-string return input === undefined ? "" : String(input) } diff --git a/packages/opencode/src/plugin/github-copilot/copilot.ts b/packages/opencode/src/plugin/github-copilot/copilot.ts index eeea21924..c1318287c 100644 --- a/packages/opencode/src/plugin/github-copilot/copilot.ts +++ b/packages/opencode/src/plugin/github-copilot/copilot.ts @@ -93,7 +93,7 @@ export async function CopilotAuthPlugin(input: PluginInput): Promise<Hooks> { const info = await getAuth() if (info.type !== "oauth") return fetch(request, init) - const url = request instanceof URL ? request.href : request.toString() + const url = request instanceof URL ? request.href : typeof request === "string" ? request : request.url const { isVision, isAgent } = iife(() => { try { const body = typeof init?.body === "string" ? JSON.parse(init.body) : init?.body diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index a0d3e2258..5fa39441c 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -274,7 +274,7 @@ export namespace ProviderTransform { // Check for empty base64 image data if (part.type === "image") { - const imageStr = part.image.toString() + const imageStr = String(part.image) if (imageStr.startsWith("data:")) { const match = imageStr.match(/^data:([^;]+);base64,(.*)$/) if (match && (!match[2] || match[2].length === 0)) { @@ -286,7 +286,7 @@ export namespace ProviderTransform { } } - const mime = part.type === "image" ? part.image.toString().split(";")[0].replace("data:", "") : part.mediaType + const mime = part.type === "image" ? String(part.image).split(";")[0].replace("data:", "") : part.mediaType const filename = part.type === "file" ? part.filename : undefined const modality = mimeToModality(mime) if (!modality) return part diff --git a/packages/opencode/src/pty/service.ts b/packages/opencode/src/pty/service.ts index a4ebd0696..0c810be88 100644 --- a/packages/opencode/src/pty/service.ts +++ b/packages/opencode/src/pty/service.ts @@ -346,7 +346,7 @@ export const layer = Layer.effect( return { onMessage: (message: string | ArrayBuffer) => { - session.process.write(String(message)) + session.process.write(typeof message === "string" ? message : new TextDecoder().decode(message)) }, onClose: () => { log.info("client disconnected from session", { id }) diff --git a/packages/opencode/src/snapshot/snapshot.ts b/packages/opencode/src/snapshot/snapshot.ts index 8d8118131..7a5c0a4dc 100644 --- a/packages/opencode/src/snapshot/snapshot.ts +++ b/packages/opencode/src/snapshot/snapshot.ts @@ -116,7 +116,7 @@ export const layer: Layer.Layer< Effect.succeed({ code: ChildProcessSpawner.ExitCode(1), text: "", - stderr: String(err), + stderr: err instanceof Error ? err.message : String(err), }), ), ) diff --git a/packages/opencode/src/tool/apply_patch.ts b/packages/opencode/src/tool/apply_patch.ts index b9877d8fe..2d8a50101 100644 --- a/packages/opencode/src/tool/apply_patch.ts +++ b/packages/opencode/src/tool/apply_patch.ts @@ -145,7 +145,15 @@ export const ApplyPatchTool = Tool.define( case "delete": { const contentToDelete = yield* afs .readFileString(filePath) - .pipe(Effect.catch((error) => Effect.fail(new Error(`apply_patch verification failed: ${error}`)))) + .pipe( + Effect.catch((error) => + Effect.fail( + new Error( + `apply_patch verification failed: ${error instanceof Error ? error.message : String(error)}`, + ), + ), + ), + ) const deleteDiff = trimDiff(createTwoFilesPatch(filePath, filePath, contentToDelete, "")) const deletions = contentToDelete.split("\n").length diff --git a/packages/opencode/src/util/error.ts b/packages/opencode/src/util/error.ts index ea1c79178..75fef9fc9 100644 --- a/packages/opencode/src/util/error.ts +++ b/packages/opencode/src/util/error.ts @@ -60,6 +60,7 @@ export function errorData(error: unknown) { acc[key] = value return acc } + // oxlint-disable-next-line no-base-to-string -- intentional coercion of arbitrary error properties acc[key] = value instanceof Error ? value.message : String(value) return acc }, {}) diff --git a/packages/opencode/src/v2/session-entry.ts b/packages/opencode/src/v2/session-entry.ts index a60d8c6c7..490f18422 100644 --- a/packages/opencode/src/v2/session-entry.ts +++ b/packages/opencode/src/v2/session-entry.ts @@ -202,6 +202,7 @@ export namespace SessionEntry { case "tool.input.delta": { if (!pendingAssistant) break const match = pendingAssistant.content.findLast((x) => x.type === "tool") + // oxlint-disable-next-line no-base-to-string -- event.delta is a Schema.String (runtime string) if (match) match.state.input += event.delta break } diff --git a/packages/opencode/test/config/config.test.ts b/packages/opencode/test/config/config.test.ts index bc9fe5b01..6a79cf644 100644 --- a/packages/opencode/test/config/config.test.ts +++ b/packages/opencode/test/config/config.test.ts @@ -1801,7 +1801,7 @@ test("project config overrides remote well-known config", async () => { const originalFetch = globalThis.fetch let fetchedUrl: string | undefined globalThis.fetch = mock((url: string | URL | Request) => { - const urlStr = url.toString() + const urlStr = url instanceof Request ? url.url : url instanceof URL ? url.href : url if (urlStr.includes(".well-known/opencode")) { fetchedUrl = urlStr return Promise.resolve( @@ -1858,7 +1858,7 @@ test("wellknown URL with trailing slash is normalized", async () => { const originalFetch = globalThis.fetch let fetchedUrl: string | undefined globalThis.fetch = mock((url: string | URL | Request) => { - const urlStr = url.toString() + const urlStr = url instanceof Request ? url.url : url instanceof URL ? url.href : url if (urlStr.includes(".well-known/opencode")) { fetchedUrl = urlStr return Promise.resolve( diff --git a/packages/shared/src/util/retry.ts b/packages/shared/src/util/retry.ts index 0014a604c..831d23800 100644 --- a/packages/shared/src/util/retry.ts +++ b/packages/shared/src/util/retry.ts @@ -19,6 +19,7 @@ const TRANSIENT_MESSAGES = [ function isTransientError(error: unknown): boolean { if (!error) return false + // oxlint-disable-next-line no-base-to-string -- error is unknown, intentional coercion for message matching const message = String(error instanceof Error ? error.message : error).toLowerCase() return TRANSIENT_MESSAGES.some((m) => message.includes(m)) } diff --git a/packages/shared/test/util/effect-flock.test.ts b/packages/shared/test/util/effect-flock.test.ts index 6e094c2e1..bd71e4f02 100644 --- a/packages/shared/test/util/effect-flock.test.ts +++ b/packages/shared/test/util/effect-flock.test.ts @@ -317,6 +317,7 @@ describe("util.effect-flock", () => { }) const result = yield* flock.withLock(Effect.void, "eflock:perm", dir).pipe(Effect.exit) + // oxlint-disable-next-line no-base-to-string -- Exit has a useful toString for test assertions expect(String(result)).toContain("PermissionDenied") yield* Effect.promise(() => fs.chmod(dir, 0o700).then(() => fs.rm(tmp, { recursive: true, force: true }))) }), diff --git a/packages/storybook/.storybook/mocks/app/context/language.ts b/packages/storybook/.storybook/mocks/app/context/language.ts index f75240b9c..c3317ca2e 100644 --- a/packages/storybook/.storybook/mocks/app/context/language.ts +++ b/packages/storybook/.storybook/mocks/app/context/language.ts @@ -60,6 +60,7 @@ function render(template: string, params?: Record<string, unknown>) { return template.replace(/\{\{([^}]+)\}\}/g, (_, key: string) => { const value = params[key.trim()] if (value === undefined || value === null) return "" + // oxlint-disable-next-line no-base-to-string -- value is Record<string, unknown>, always coerced intentionally return String(value) }) } diff --git a/packages/ui/src/components/file.tsx b/packages/ui/src/components/file.tsx index fd902b2e0..633b23b70 100644 --- a/packages/ui/src/components/file.tsx +++ b/packages/ui/src/components/file.tsx @@ -698,6 +698,7 @@ function TextViewer<T>(props: TextFileProps<T>) { if (typeof value === "string") return value if (Array.isArray(value)) return value.join("\n") if (value == null) return "" + // oxlint-disable-next-line no-base-to-string -- file contents cast to unknown, coercion is intentional return String(value) } @@ -712,11 +713,13 @@ function TextViewer<T>(props: TextFileProps<T>) { if (typeof value === "string") return value.length if (Array.isArray(value)) { return value.reduce( + // oxlint-disable-next-line no-base-to-string -- array parts coerced intentionally (sum, part) => sum + (typeof part === "string" ? part.length + 1 : String(part).length + 1), 0, ) } if (value == null) return 0 + // oxlint-disable-next-line no-base-to-string -- file contents cast to unknown, coercion is intentional return String(value).length }) diff --git a/packages/ui/src/components/session-turn.tsx b/packages/ui/src/components/session-turn.tsx index 2e5f9e38b..75279a90e 100644 --- a/packages/ui/src/components/session-turn.tsx +++ b/packages/ui/src/components/session-turn.tsx @@ -313,6 +313,7 @@ export function SessionTurn( const msg = error()?.data?.message if (typeof msg === "string") return unwrap(msg) if (msg === undefined || msg === null) return "" + // oxlint-disable-next-line no-base-to-string -- msg is unknown from error data, coercion is intentional return unwrap(String(msg)) }) diff --git a/packages/web/src/components/share/part.tsx b/packages/web/src/components/share/part.tsx index c7d177df7..34cfe3f42 100644 --- a/packages/web/src/components/share/part.tsx +++ b/packages/web/src/components/share/part.tsx @@ -730,7 +730,13 @@ export function FallbackTool(props: ToolProps) { <> <div></div> <div>{arg[0]}</div> - <div>{String(arg[1] ?? "")}</div> + <div> + {typeof arg[1] === "string" || typeof arg[1] === "number" || typeof arg[1] === "boolean" + ? String(arg[1]) + : arg[1] == null + ? "" + : JSON.stringify(arg[1])} + </div> </> )} </For> |
