diff --git a/.opencode/tool/github-pr-search.ts b/.opencode/tool/github-pr-search.ts index 927e68fd73..8bc8c554aa 100644 --- a/.opencode/tool/github-pr-search.ts +++ b/.opencode/tool/github-pr-search.ts @@ -7,7 +7,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) { Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, Accept: "application/vnd.github+json", "Content-Type": "application/json", - ...options.headers, + ...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers), }, }) if (!response.ok) { diff --git a/.opencode/tool/github-triage.ts b/.opencode/tool/github-triage.ts index c06d2407fe..dcbfc8d054 100644 --- a/.opencode/tool/github-triage.ts +++ b/.opencode/tool/github-triage.ts @@ -28,7 +28,7 @@ async function githubFetch(endpoint: string, options: RequestInit = {}) { Authorization: `Bearer ${process.env.GITHUB_TOKEN}`, Accept: "application/vnd.github+json", "Content-Type": "application/json", - ...options.headers, + ...(options.headers instanceof Headers ? Object.fromEntries(options.headers.entries()) : options.headers), }, }) if (!response.ok) { diff --git a/.oxlintrc.json b/.oxlintrc.json index 0875f38326..f1ca1ff46f 100644 --- a/.oxlintrc.json +++ b/.oxlintrc.json @@ -1,10 +1,51 @@ { "$schema": "https://raw.githubusercontent.com/nicolo-ribaudo/oxc-project.github.io/refs/heads/json-schema/src/public/.oxlintrc.schema.json", + "options": { + "typeAware": true + }, + "categories": { + "suspicious": "warn" + }, "rules": { + "typescript/no-base-to-string": "warn", // Effect uses `function*` with Effect.gen/Effect.fnUntraced that don't always yield "require-yield": "off", // SolidJS uses `let ref: T | undefined` for JSX ref bindings assigned at runtime - "no-unassigned-vars": "off" + "no-unassigned-vars": "off", + // SolidJS tracks reactive deps by reading properties inside createEffect + "no-unused-expressions": "off", + // Intentional control char matching (ANSI escapes, null byte sanitization) + "no-control-regex": "off", + // SST and plugin tools require triple-slash references + "triple-slash-reference": "off", + + // Suspicious category: suppress noisy rules + // Effect's nested function* closures inherently shadow outer scope + "no-shadow": "off", + // Namespace-heavy codebase makes this too noisy + "unicorn/consistent-function-scoping": "off", + // Opinionated — .sort()/.reverse() mutation is fine in this codebase + "unicorn/no-array-sort": "off", + "unicorn/no-array-reverse": "off", + // Not relevant — this isn't a DOM event handler codebase + "unicorn/prefer-add-event-listener": "off", + // Bundler handles module resolution + "unicorn/require-module-specifiers": "off", + // postMessage target origin not relevant for this codebase + "unicorn/require-post-message-target-origin": "off", + // Side-effectful constructors are intentional in some places + "no-new": "off", + + // Type-aware: catch unhandled promises + "typescript/no-floating-promises": "warn", + // Warn when spreading non-plain objects (Headers, class instances, etc.) + "typescript/no-misused-spread": "warn" }, - "ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts"] + "options": { + "typeAware": true + }, + "options": { + "typeAware": true + }, + "ignorePatterns": ["**/node_modules", "**/dist", "**/.build", "**/.sst", "**/*.d.ts", "**/sdk.gen.ts"] } diff --git a/bun.lock b/bun.lock index 15567d9516..870606ad18 100644 --- a/bun.lock +++ b/bun.lock @@ -20,6 +20,7 @@ "glob": "13.0.5", "husky": "9.1.7", "oxlint": "1.60.0", + "oxlint-tsgolint": "0.21.0", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", @@ -428,7 +429,6 @@ "@opencode-ai/plugin": "workspace:*", "@opencode-ai/script": "workspace:*", "@opencode-ai/sdk": "workspace:*", - "@opencode-ai/server": "workspace:*", "@openrouter/ai-sdk-provider": "2.5.1", "@opentelemetry/api": "1.9.0", "@opentelemetry/context-async-hooks": "2.6.1", @@ -578,17 +578,6 @@ "typescript": "catalog:", }, }, - "packages/server": { - "name": "@opencode-ai/server", - "version": "1.4.6", - "dependencies": { - "effect": "catalog:", - }, - "devDependencies": { - "@typescript/native-preview": "catalog:", - "typescript": "catalog:", - }, - }, "packages/shared": { "name": "@opencode-ai/shared", "version": "1.4.6", @@ -606,7 +595,9 @@ "zod": "catalog:", }, "devDependencies": { + "@tsconfig/bun": "catalog:", "@types/bun": "catalog:", + "@types/npmcli__arborist": "6.3.3", "@types/semver": "catalog:", }, }, @@ -1872,8 +1863,6 @@ "@opencode-ai/sdk": ["@opencode-ai/sdk@workspace:packages/sdk/js"], - "@opencode-ai/server": ["@opencode-ai/server@workspace:packages/server"], - "@opencode-ai/shared": ["@opencode-ai/shared@workspace:packages/shared"], "@opencode-ai/slack": ["@opencode-ai/slack@workspace:packages/slack"], @@ -1998,6 +1987,18 @@ "@oxc-transform/binding-win32-x64-msvc": ["@oxc-transform/binding-win32-x64-msvc@0.96.0", "", { "os": "win32", "cpu": "x64" }, "sha512-0fI0P0W7bSO/GCP/N5dkmtB9vBqCA4ggo1WmXTnxNJVmFFOtcA1vYm1I9jl8fxo+sucW2WnlpnI4fjKdo3JKxA=="], + "@oxlint-tsgolint/darwin-arm64": ["@oxlint-tsgolint/darwin-arm64@0.21.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-P20j3MLqfwIT+94qGU3htC7dWp4pXGZW1p1p7FRUzu1aopq7c9nPCgf0W/WjktqQ57+iuTq9mbSlwWinl6+H1A=="], + + "@oxlint-tsgolint/darwin-x64": ["@oxlint-tsgolint/darwin-x64@0.21.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-81TmmuBcPedEA0MwRmObuQuXnCprS1UiHQWGe7pseqNAJzUWXeAPrayqKTACX92VpruJI+yvY0XJrFp11PpcTA=="], + + "@oxlint-tsgolint/linux-arm64": ["@oxlint-tsgolint/linux-arm64@0.21.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-sbjBr6zDduX8rNO0PTjhf7VYLCPWqdijWiMPp8e10qu6Tam1GdaVLaLlX8QrNupTgglO1GvqqgY/jcacWL8a6g=="], + + "@oxlint-tsgolint/linux-x64": ["@oxlint-tsgolint/linux-x64@0.21.0", "", { "os": "linux", "cpu": "x64" }, "sha512-jNrOcy53R5TJQfrK444Cm60bW9437xDoxPbm3AdvFSo/fhdFMllawc7uZC2Wzr+EAjTkW13K8R4QHzsUdBG9fQ=="], + + "@oxlint-tsgolint/win32-arm64": ["@oxlint-tsgolint/win32-arm64@0.21.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-xWeRxJJILDE4b9UqHEWGBxcBc1TUS6zWHhxcyxTZMwf4q3wdKeu0OHYAcwLGJzoSjEIf6FTjyfPiRNil2oqsdg=="], + + "@oxlint-tsgolint/win32-x64": ["@oxlint-tsgolint/win32-x64@0.21.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Ob9AA9teI8ckPo1whV1smLr5NrqwgBv/8boDbK0YZG+fKgNGRwr1hBj1ORgFWOQaUBv+5njp5A0RAfJJjQ95QQ=="], + "@oxlint/binding-android-arm-eabi": ["@oxlint/binding-android-arm-eabi@1.60.0", "", { "os": "android", "cpu": "arm" }, "sha512-YdeJKaZckDQL1qa62a1aKq/goyq48aX3yOxaaWqWb4sau4Ee4IiLbamftNLU3zbePky6QsDj6thnSSzHRBjDfA=="], "@oxlint/binding-android-arm64": ["@oxlint/binding-android-arm64@1.60.0", "", { "os": "android", "cpu": "arm64" }, "sha512-7ANS7PpXCfq84xZQ8E5WPs14gwcuPcl+/8TFNXfpSu0CQBXz3cUo2fDpHT8v8HJN+Ut02eacvMAzTnc9s6X4tw=="], @@ -4806,6 +4807,8 @@ "oxlint": ["oxlint@1.60.0", "", { "optionalDependencies": { "@oxlint/binding-android-arm-eabi": "1.60.0", "@oxlint/binding-android-arm64": "1.60.0", "@oxlint/binding-darwin-arm64": "1.60.0", "@oxlint/binding-darwin-x64": "1.60.0", "@oxlint/binding-freebsd-x64": "1.60.0", "@oxlint/binding-linux-arm-gnueabihf": "1.60.0", "@oxlint/binding-linux-arm-musleabihf": "1.60.0", "@oxlint/binding-linux-arm64-gnu": "1.60.0", "@oxlint/binding-linux-arm64-musl": "1.60.0", "@oxlint/binding-linux-ppc64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-gnu": "1.60.0", "@oxlint/binding-linux-riscv64-musl": "1.60.0", "@oxlint/binding-linux-s390x-gnu": "1.60.0", "@oxlint/binding-linux-x64-gnu": "1.60.0", "@oxlint/binding-linux-x64-musl": "1.60.0", "@oxlint/binding-openharmony-arm64": "1.60.0", "@oxlint/binding-win32-arm64-msvc": "1.60.0", "@oxlint/binding-win32-ia32-msvc": "1.60.0", "@oxlint/binding-win32-x64-msvc": "1.60.0" }, "peerDependencies": { "oxlint-tsgolint": ">=0.18.0" }, "optionalPeers": ["oxlint-tsgolint"], "bin": { "oxlint": "bin/oxlint" } }, "sha512-tnRzTWiWJ9pg3ftRWnD0+Oqh78L6ZSwcEudvCZaER0PIqiAnNyXj5N1dPwjmNpDalkKS9m/WMLN1CTPUBPmsgw=="], + "oxlint-tsgolint": ["oxlint-tsgolint@0.21.0", "", { "optionalDependencies": { "@oxlint-tsgolint/darwin-arm64": "0.21.0", "@oxlint-tsgolint/darwin-x64": "0.21.0", "@oxlint-tsgolint/linux-arm64": "0.21.0", "@oxlint-tsgolint/linux-x64": "0.21.0", "@oxlint-tsgolint/win32-arm64": "0.21.0", "@oxlint-tsgolint/win32-x64": "0.21.0" }, "bin": { "tsgolint": "bin/tsgolint.js" } }, "sha512-HiWPhANwRnN1pZJQ2SgNB3WRR+1etLJHmRzQ/MJhyINsEIaOUCjxhlXJKbEaVUwdnyXwRWqo/P9Fx21lz0/mSg=="], + "p-cancelable": ["p-cancelable@2.1.1", "", {}, "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg=="], "p-defer": ["p-defer@3.0.0", "", {}, "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw=="], diff --git a/github/index.ts b/github/index.ts index 6bfa964623..51ee2a46a5 100644 --- a/github/index.ts +++ b/github/index.ts @@ -281,7 +281,7 @@ async function assertOpencodeConnected() { }) connected = true break - } catch (e) {} + } catch {} await sleep(300) } while (retry++ < 30) @@ -513,7 +513,7 @@ async function subscribeSessionEvents() { const decoder = new TextDecoder() let text = "" - ;(async () => { + void (async () => { while (true) { try { const { done, value } = await reader.read() @@ -542,7 +542,7 @@ async function subscribeSessionEvents() { ? JSON.stringify(part.state.input) : "Unknown" console.log() - console.log(color + `|`, "\x1b[0m\x1b[2m" + ` ${tool.padEnd(7, " ")}`, "", "\x1b[0m" + title) + console.log(`${color}|`, `\x1b[0m\x1b[2m ${tool.padEnd(7, " ")}`, "", `\x1b[0m${title}`) } if (part.type === "text") { @@ -561,7 +561,7 @@ async function subscribeSessionEvents() { if (evt.properties.info.id !== session.id) continue session = evt.properties.info } - } catch (e) { + } catch { // Ignore parse errors } } @@ -576,7 +576,7 @@ async function subscribeSessionEvents() { async function summarize(response: string) { try { return await chat(`Summarize the following in less than 40 characters:\n\n${response}`) - } catch (e) { + } catch { if (isScheduleEvent()) { return "Scheduled task changes" } @@ -776,7 +776,7 @@ async function assertPermissions() { console.log(` permission: ${permission}`) } catch (error) { console.error(`Failed to check permissions: ${error}`) - throw new Error(`Failed to check permissions for user ${actor}: ${error}`) + throw new Error(`Failed to check permissions for user ${actor}: ${error}`, { cause: error }) } if (!["admin", "write"].includes(permission)) throw new Error(`User ${actor} does not have write permissions`) diff --git a/infra/enterprise.ts b/infra/enterprise.ts index 22b4c6f44e..dc336a6843 100644 --- a/infra/enterprise.ts +++ b/infra/enterprise.ts @@ -1,9 +1,9 @@ import { SECRET } from "./secret" -import { domain, shortDomain } from "./stage" +import { shortDomain } from "./stage" const storage = new sst.cloudflare.Bucket("EnterpriseStorage") -const teams = new sst.cloudflare.x.SolidStart("Teams", { +new sst.cloudflare.x.SolidStart("Teams", { domain: shortDomain, path: "packages/enterprise", buildCommand: "bun run build:cloudflare", diff --git a/nix/hashes.json b/nix/hashes.json index a12e6f7e5e..e9795e5c37 100644 --- a/nix/hashes.json +++ b/nix/hashes.json @@ -1,8 +1,8 @@ { "nodeModules": { - "x86_64-linux": "sha256-PvIx2g1J5QIUIzkz2ABaAM4K/k/+xlBPDUExoOJNNuo=", - "aarch64-linux": "sha256-YTAL+P13L5hgNJdDSiBED/UNa5zdTntnUUYDYL+Jdzo=", - "aarch64-darwin": "sha256-y2VCJifYAp+H0lpDcJ0QfKNMG00Q/usFElaUIpdc8Vs=", - "x86_64-darwin": "sha256-yz8edIlqLp06Y95ad8YjKz5azP7YATPle4TcDx6lM+U=" + "x86_64-linux": "sha256-NJAK+cPjwn+2ojDLyyDmBQyx2pD+rILetp7VCylgjek=", + "aarch64-linux": "sha256-q8NTtFQJoyM7TTvErGA6RtmUscxoZKD/mj9N6S5YhkA=", + "aarch64-darwin": "sha256-/ccoSZNLef6j9j14HzpVqhKCR+czM3mhPKPH51mHO24=", + "x86_64-darwin": "sha256-6Pd10sMHL/5ZoWNvGPwPn4/AIs1TKjt/3gFyrVpBaE0=" } } diff --git a/package.json b/package.json index 8c5ae91955..5fecc09922 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "glob": "13.0.5", "husky": "9.1.7", "oxlint": "1.60.0", + "oxlint-tsgolint": "0.21.0", "prettier": "3.6.2", "semver": "^7.6.0", "sst": "3.18.10", diff --git a/packages/app/src/addons/serialize.test.ts b/packages/app/src/addons/serialize.test.ts index 7f6780557d..6828e60f84 100644 --- a/packages/app/src/addons/serialize.test.ts +++ b/packages/app/src/addons/serialize.test.ts @@ -180,8 +180,8 @@ describe("SerializeAddon", () => { await writeAndWait(term, input) const origLine = term.buffer.active.getLine(0) - const origFg = origLine!.getCell(0)!.getFgColor() - const origBg = origLine!.getCell(0)!.getBgColor() + const _origFg = origLine!.getCell(0)!.getFgColor() + const _origBg = origLine!.getCell(0)!.getBgColor() expect(origLine!.getCell(0)!.isBold()).toBe(1) const serialized = addon.serialize({ range: { start: 0, end: 0 } }) diff --git a/packages/app/src/addons/serialize.ts b/packages/app/src/addons/serialize.ts index 4cab55b3f2..3823fb443a 100644 --- a/packages/app/src/addons/serialize.ts +++ b/packages/app/src/addons/serialize.ts @@ -258,8 +258,8 @@ class StringSerializeHandler extends BaseSerializeHandler { } protected _beforeSerialize(rows: number, start: number, _end: number): void { - this._allRows = new Array(rows) - this._allRowSeparators = new Array(rows) + this._allRows = Array.from({ length: rows }) + this._allRowSeparators = Array.from({ length: rows }) this._rowIndex = 0 this._currentRow = "" diff --git a/packages/app/src/app.tsx b/packages/app/src/app.tsx index 35fd36cca3..dbe1074484 100644 --- a/packages/app/src/app.tsx +++ b/packages/app/src/app.tsx @@ -10,7 +10,7 @@ import { ThemeProvider } from "@opencode-ai/ui/theme/context" import { MetaProvider } from "@solidjs/meta" import { type BaseRouterProps, Navigate, Route, Router } from "@solidjs/router" import { QueryClient, QueryClientProvider } from "@tanstack/solid-query" -import { type Duration, Effect } from "effect" +import { Effect } from "effect" import { type Component, createMemo, @@ -121,10 +121,10 @@ function SessionProviders(props: ParentProps) { function RouterRoot(props: ParentProps<{ appChildren?: JSX.Element }>) { return ( - }> - {props.appChildren} - {props.children} - + {/*}>*/} + {props.appChildren} + {props.children} + {/**/} ) } @@ -156,11 +156,6 @@ export function AppBaseProviders(props: ParentProps<{ locale?: Locale }>) { ) } -const effectMinDuration = - (duration: Duration.Input) => - (e: Effect.Effect) => - Effect.all([e, Effect.sleep(duration)], { concurrency: "unbounded" }).pipe(Effect.map((v) => v[0])) - function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) { const server = useServer() const checkServerHealth = useCheckServerHealth() @@ -189,32 +184,41 @@ function ConnectionGate(props: ParentProps<{ disableHealthCheck?: boolean }>) { ) return ( - } > + {/* + + + } + >*/} + {checkMode() === "blocking" ? startupHealthCheck() : startupHealthCheck.latest} { - if (checkMode() === "background") healthCheckActions.refetch() + if (checkMode() === "background") void healthCheckActions.refetch() }} onServerSelected={(key) => { setCheckMode("blocking") server.setActive(key) - healthCheckActions.refetch() + void healthCheckActions.refetch() }} /> } > {props.children} - + {/**/} + ) } diff --git a/packages/app/src/components/dialog-connect-provider.tsx b/packages/app/src/components/dialog-connect-provider.tsx index 41225d02aa..e305743799 100644 --- a/packages/app/src/components/dialog-connect-provider.tsx +++ b/packages/app/src/components/dialog-connect-provider.tsx @@ -327,7 +327,7 @@ export function DialogConnectProvider(props: { provider: string }) { if (loading()) return if (methods().length === 1) { auto = true - selectMethod(0) + void selectMethod(0) } }) @@ -373,7 +373,7 @@ export function DialogConnectProvider(props: { provider: string }) { key={(m) => m?.label} onSelect={async (selected, index) => { if (!selected) return - selectMethod(index) + void selectMethod(index) }} > {(i) => ( diff --git a/packages/app/src/components/dialog-select-file.tsx b/packages/app/src/components/dialog-select-file.tsx index a0347a0399..186906f920 100644 --- a/packages/app/src/components/dialog-select-file.tsx +++ b/packages/app/src/components/dialog-select-file.tsx @@ -348,8 +348,8 @@ export function DialogSelectFile(props: { mode?: DialogSelectFileMode; onOpenFil const open = (path: string) => { const value = file.tab(path) - tabs().open(value) - file.load(path) + void tabs().open(value) + void file.load(path) if (!view().reviewPanel.opened()) view().reviewPanel.open() layout.fileTree.setTab("all") props.onOpenFile?.(path) diff --git a/packages/app/src/components/dialog-select-server.tsx b/packages/app/src/components/dialog-select-server.tsx index ca4c42a376..dd92edec3e 100644 --- a/packages/app/src/components/dialog-select-server.tsx +++ b/packages/app/src/components/dialog-select-server.tsx @@ -344,7 +344,7 @@ export function DialogSelectServer() { createEffect(() => { items() - refreshHealth() + void refreshHealth() const interval = setInterval(refreshHealth, 10_000) onCleanup(() => clearInterval(interval)) }) @@ -498,7 +498,7 @@ export function DialogSelectServer() { async function handleRemove(url: ServerConnection.Key) { server.remove(url) if ((await platform.getDefaultServer?.()) === url) { - platform.setDefaultServer?.(null) + void platform.setDefaultServer?.(null) } } @@ -536,7 +536,7 @@ export function DialogSelectServer() { items={sortedItems} key={(x) => x.http.url} onSelect={(x) => { - if (x) select(x) + if (x) void select(x) }} divider={true} class="px-5 [&_[data-slot=list-search-wrapper]]:w-full [&_[data-slot=list-scroll]]h-[300px] [&_[data-slot=list-scroll]]:overflow-y-auto [&_[data-slot=list-items]]:bg-surface-base [&_[data-slot=list-items]]:rounded-md [&_[data-slot=list-item]]:min-h-14 [&_[data-slot=list-item]]:p-3 [&_[data-slot=list-item]]:!bg-transparent" diff --git a/packages/app/src/components/file-tree.tsx b/packages/app/src/components/file-tree.tsx index 8fbecf6712..211ce05ef0 100644 --- a/packages/app/src/components/file-tree.tsx +++ b/packages/app/src/components/file-tree.tsx @@ -14,7 +14,6 @@ import { Switch, untrack, type ComponentProps, - type JSXElement, type ParentProps, } from "solid-js" import { Dynamic } from "solid-js/web" diff --git a/packages/app/src/components/prompt-input.tsx b/packages/app/src/components/prompt-input.tsx index 8ddb10a906..156b0b3a4a 100644 --- a/packages/app/src/components/prompt-input.tsx +++ b/packages/app/src/components/prompt-input.tsx @@ -54,6 +54,8 @@ import { PromptImageAttachments } from "./prompt-input/image-attachments" import { PromptDragOverlay } from "./prompt-input/drag-overlay" import { promptPlaceholder } from "./prompt-input/placeholder" import { ImagePreview } from "@opencode-ai/ui/image-preview" +import { useQuery } from "@tanstack/solid-query" +import { loadAgentsQuery, loadProvidersQuery } from "@/context/global-sync/bootstrap" interface PromptInputProps { class?: string @@ -100,6 +102,7 @@ const NON_EMPTY_TEXT = /[^\s\u200B]/ export const PromptInput: Component = (props) => { const sdk = useSDK() + const sync = useSync() const local = useLocal() const files = useFile() @@ -212,9 +215,9 @@ export const PromptInput: Component = (props) => { if (!view().reviewPanel.opened()) view().reviewPanel.open() layout.fileTree.setTab("all") const tab = files.tab(item.path) - tabs().open(tab) + void tabs().open(tab) tabs().setActive(tab) - Promise.resolve(files.load(item.path)).finally(() => queueCommentFocus()) + void Promise.resolve(files.load(item.path)).finally(() => queueCommentFocus()) } const recent = createMemo(() => { @@ -1139,7 +1142,7 @@ export const PromptInput: Component = (props) => { } if (working()) { - abort() + void abort() event.preventDefault() event.stopPropagation() return @@ -1205,7 +1208,7 @@ export const PromptInput: Component = (props) => { return } if (working()) { - abort() + void abort() event.preventDefault() } return @@ -1245,10 +1248,18 @@ export const PromptInput: Component = (props) => { ) { return } - handleSubmit(event) + void handleSubmit(event) } } + const agentsQuery = useQuery(() => loadAgentsQuery(sdk.directory)) + const agentsLoading = () => agentsQuery.isLoading + + const globalProvidersQuery = useQuery(() => loadProvidersQuery(null)) + const providersQuery = useQuery(() => loadProvidersQuery(sdk.directory)) + + const providersLoading = () => agentsLoading() || providersQuery.isLoading || globalProvidersQuery.isLoading + return (
= (props) => { {language.t("prompt.mode.shell")}
-
-
- - { + local.agent.set(value) + restoreFocus() + }} + class="capitalize max-w-[160px] text-text-base" + valueClass="truncate text-13-regular text-text-base" + triggerStyle={control()} + triggerProps={{ "data-action": "prompt-agent" }} + variant="ghost" + /> + +
+ + + +
+ 0} + fallback={ + + + + } + > - + - } - > + +
+
- (x === "default" ? language.t("common.default") : x)} + onSelect={(value) => { + local.model.variant.set(value === "default" ? undefined : value) + restoreFocus() }} - onClose={restoreFocus} - > - - - - - {local.model.current()?.name ?? language.t("dialog.model.select.title")} - - - + class="capitalize max-w-[160px] text-text-base" + valueClass="truncate text-13-regular text-text-base" + triggerStyle={control()} + triggerProps={{ "data-action": "prompt-model-variant" }} + variant="ghost" + /> - -
-
- - - +