diff --git a/packages/app/src/components/dialog-select-provider.tsx b/packages/app/src/components/dialog-select-provider.tsx
index e53738399a..226f6a0bb4 100644
--- a/packages/app/src/components/dialog-select-provider.tsx
+++ b/packages/app/src/components/dialog-select-provider.tsx
@@ -74,7 +74,9 @@ export const DialogSelectProvider: Component = () => {
{language.t("dialog.provider.tag.recommended")}
- {(value) => {value()}
}
+
+ {(value) => {value}
}
+
{language.t("dialog.provider.tag.recommended")}
diff --git a/packages/app/src/components/model-tooltip.tsx b/packages/app/src/components/model-tooltip.tsx
index 53164dae85..08b0cb48f2 100644
--- a/packages/app/src/components/model-tooltip.tsx
+++ b/packages/app/src/components/model-tooltip.tsx
@@ -77,10 +77,10 @@ export const ModelTooltip: Component<{ model: ModelInfo; latest?: boolean; free?
return (
{title()}
-
+
{(value) => (
- {language.t("model.tooltip.allows", { inputs: value() })}
+ {language.t("model.tooltip.allows", { inputs: value })}
)}
diff --git a/packages/app/src/components/prompt-input/context-items.tsx b/packages/app/src/components/prompt-input/context-items.tsx
index b138fe3ef6..8a3c556b3c 100644
--- a/packages/app/src/components/prompt-input/context-items.tsx
+++ b/packages/app/src/components/prompt-input/context-items.tsx
@@ -52,12 +52,10 @@ export const PromptContextItems: Component = (props) => {
{label}
-
+
{(sel) => (
- {sel().startLine === sel().endLine
- ? `:${sel().startLine}`
- : `:${sel().startLine}-${sel().endLine}`}
+ {sel.startLine === sel.endLine ? `:${sel.startLine}` : `:${sel.startLine}-${sel.endLine}`}
)}
@@ -74,8 +72,8 @@ export const PromptContextItems: Component = (props) => {
aria-label={props.t("prompt.context.removeFile")}
/>
-
- {(comment) => {comment()}
}
+
+ {(comment) => {comment}
}
diff --git a/packages/app/src/components/server/server-row.tsx b/packages/app/src/components/server/server-row.tsx
index 5bb290ec30..78862d2c54 100644
--- a/packages/app/src/components/server/server-row.tsx
+++ b/packages/app/src/components/server/server-row.tsx
@@ -78,6 +78,7 @@ export function ServerRow(props: ServerRowProps) {
@@ -86,20 +87,20 @@ export function ServerRow(props: ServerRowProps) {
}
>
- {(badge) => badge()}
+ {(badge) => badge}
-
+
{(conn) => (
- {conn().http.username ? (
- {conn().http.username}
+ {conn.http.username ? (
+ {conn.http.username}
) : (
no username
)}
- {conn().http.password && ••••••••}
+ {conn.http.password && ••••••••}
)}
diff --git a/packages/app/src/components/session-context-usage.tsx b/packages/app/src/components/session-context-usage.tsx
index 08ae4d3194..7be9b51694 100644
--- a/packages/app/src/components/session-context-usage.tsx
+++ b/packages/app/src/components/session-context-usage.tsx
@@ -73,15 +73,15 @@ export function SessionContextUsage(props: SessionContextUsageProps) {
const tooltipValue = () => (
-
+
{(ctx) => (
<>
- {ctx().total.toLocaleString(language.intl())}
+ {ctx.total.toLocaleString(language.intl())}
{language.t("context.usage.tokens")}
- {ctx().usage ?? 0}%
+ {ctx.usage ?? 0}%
{language.t("context.usage.usage")}
>
diff --git a/packages/app/src/components/session/session-context-tab.tsx b/packages/app/src/components/session/session-context-tab.tsx
index 39eb4b4c0e..ba66f88296 100644
--- a/packages/app/src/components/session/session-context-tab.tsx
+++ b/packages/app/src/components/session/session-context-tab.tsx
@@ -316,12 +316,12 @@ export function SessionContextTab() {
-
+
{(prompt) => (
{language.t("context.systemPrompt.title")}
-
+
)}
diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx
index bb4d981250..d068692f64 100644
--- a/packages/app/src/components/session/session-header.tsx
+++ b/packages/app/src/components/session/session-header.tsx
@@ -356,9 +356,9 @@ export function SessionHeader() {
return (
<>
-
+
{(mount) => (
-
+
)}
-
+
{(mount) => (
-
+
diff --git a/packages/app/src/components/session/session-new-view.tsx b/packages/app/src/components/session/session-new-view.tsx
index f2ecd51501..8ef5582ba5 100644
--- a/packages/app/src/components/session/session-new-view.tsx
+++ b/packages/app/src/components/session/session-new-view.tsx
@@ -62,14 +62,14 @@ export function NewSessionView(props: NewSessionViewProps) {
{label(current())}
-
+
{(project) => (
{language.t("session.new.lastModified")}
- {DateTime.fromMillis(project().time.updated ?? project().time.created)
+ {DateTime.fromMillis(project.time.updated ?? project.time.created)
.setLocale(language.intl())
.toRelative()}
diff --git a/packages/app/src/components/session/session-sortable-tab.tsx b/packages/app/src/components/session/session-sortable-tab.tsx
index dfda91c160..e6d2b24c78 100644
--- a/packages/app/src/components/session/session-sortable-tab.tsx
+++ b/packages/app/src/components/session/session-sortable-tab.tsx
@@ -62,7 +62,9 @@ export function SortableTab(props: { tab: string; onTabClose: (tab: string) => v
hideCloseButton
onMiddleClick={() => props.onTabClose(props.tab)}
>
- {(value) => value()}
+
+ {(value) => value}
+
diff --git a/packages/app/src/components/settings-general.tsx b/packages/app/src/components/settings-general.tsx
index 42ee4092f6..c19e4d0765 100644
--- a/packages/app/src/components/settings-general.tsx
+++ b/packages/app/src/components/settings-general.tsx
@@ -473,7 +473,7 @@ export const SettingsGeneral: Component = () => {
- {/*
+ {/*
{(_) => {
const [enabledResource, actions] = createResource(() => platform.getWslEnabled?.())
const enabled = () => (enabledResource.state === "pending" ? undefined : enabledResource.latest)
@@ -503,7 +503,7 @@ export const SettingsGeneral: Component = () => {
-
+
{(_) => {
const [valueResource, actions] = createResource(() => platform.getDisplayBackend?.())
const value = () => (valueResource.state === "pending" ? undefined : valueResource.latest)
diff --git a/packages/app/src/components/settings-providers.tsx b/packages/app/src/components/settings-providers.tsx
index a9839758b7..a2f1f0b643 100644
--- a/packages/app/src/components/settings-providers.tsx
+++ b/packages/app/src/components/settings-providers.tsx
@@ -189,8 +189,8 @@ export const SettingsProviders: Component = () => {
{language.t("dialog.provider.tag.recommended")}
-
- {(key) => {language.t(key())}}
+
+ {(key) => {language.t(key)}}
-
- {(message) => {message()}
}
+
+ {(message) => {message}
}
@@ -305,10 +305,8 @@ export const ErrorPage: Component = (props) => {
-
- {(version) => (
- {language.t("error.page.version", { version: version() })}
- )}
+
+ {(version) => {language.t("error.page.version", { version })}
}
diff --git a/packages/app/src/pages/layout/sidebar-project.tsx b/packages/app/src/pages/layout/sidebar-project.tsx
index 3c3652e38f..bafc17f880 100644
--- a/packages/app/src/pages/layout/sidebar-project.tsx
+++ b/packages/app/src/pages/layout/sidebar-project.tsx
@@ -43,10 +43,10 @@ export const ProjectDragOverlay = (props: {
}): JSX.Element => {
const project = createMemo(() => props.projects().find((p) => p.worktree === props.activeProject()))
return (
-
+
{(p) => (
)}
diff --git a/packages/app/src/pages/layout/sidebar-workspace.tsx b/packages/app/src/pages/layout/sidebar-workspace.tsx
index 43d99cf895..626c9bd15c 100644
--- a/packages/app/src/pages/layout/sidebar-workspace.tsx
+++ b/packages/app/src/pages/layout/sidebar-workspace.tsx
@@ -76,8 +76,8 @@ export const WorkspaceDragOverlay = (props: {
})
return (
-
- {(value) => {value()}
}
+
+ {(value) => {value}
}
)
}
diff --git a/packages/app/src/pages/session/message-timeline.tsx b/packages/app/src/pages/session/message-timeline.tsx
index f320a2ebbf..ba478543dc 100644
--- a/packages/app/src/pages/session/message-timeline.tsx
+++ b/packages/app/src/pages/session/message-timeline.tsx
@@ -731,12 +731,12 @@ export function MessageTimeline(props: {
class="size-3.5 shrink-0"
/>
{getFilename(comment().path)}
-
+
{(selection) => (
- {selection().startLine === selection().endLine
- ? `:${selection().startLine}`
- : `:${selection().startLine}-${selection().endLine}`}
+ {selection.startLine === selection.endLine
+ ? `:${selection.startLine}`
+ : `:${selection.startLine}-${selection.endLine}`}
)}
diff --git a/packages/app/src/show-keyed-guard.test.ts b/packages/app/src/show-keyed-guard.test.ts
new file mode 100644
index 0000000000..f46a506e6d
--- /dev/null
+++ b/packages/app/src/show-keyed-guard.test.ts
@@ -0,0 +1,61 @@
+import { describe, test } from "bun:test"
+import { join, relative, resolve } from "node:path"
+import * as ts from "typescript"
+
+const scan = async (dir: string) =>
+ Promise.all(
+ Array.from(new Bun.Glob("**/*.tsx").scanSync({ cwd: dir })).map(async (file) => {
+ const full = join(dir, file)
+ return {
+ file: full,
+ text: await Bun.file(full).text(),
+ }
+ }),
+ )
+
+const find = (file: string, text: string, root: string) => {
+ const hits: string[] = []
+ const source = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX)
+
+ const walk = (node: ts.Node): void => {
+ if (ts.isJsxElement(node) && node.openingElement.tagName.getText(source) === "Show") {
+ const keyed = node.openingElement.attributes.properties.some(
+ (prop) => ts.isJsxAttribute(prop) && prop.name.getText(source) === "keyed",
+ )
+ const child = node.children.find((child) => {
+ if (ts.isJsxText(child)) return child.getText(source).trim() !== ""
+ if (ts.isJsxExpression(child)) return child.expression !== undefined
+ return true
+ })
+
+ if (
+ !keyed &&
+ child &&
+ ts.isJsxExpression(child) &&
+ child.expression &&
+ ts.isArrowFunction(child.expression) &&
+ child.expression.parameters.length > 0
+ ) {
+ hits.push(`${relative(root, file)}:${source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1}`)
+ }
+ }
+
+ ts.forEachChild(node, walk)
+ }
+
+ walk(source)
+ return hits
+}
+
+describe("show keyed guard", () => {
+ test("app and desktop show callbacks are keyed", async () => {
+ const root = resolve(import.meta.dir, "../../..")
+ const hits = (await Promise.all([scan(import.meta.dir), scan(resolve(import.meta.dir, "../../desktop/src"))]))
+ .flat()
+ .flatMap((item) => find(item.file, item.text, root))
+
+ if (hits.length > 0) {
+ throw new Error(`non-keyed callbacks found:\n${hits.join("\n")}`)
+ }
+ })
+})
diff --git a/packages/desktop/src/index.tsx b/packages/desktop/src/index.tsx
index 9afabe918b..4577a4eca1 100644
--- a/packages/desktop/src/index.tsx
+++ b/packages/desktop/src/index.tsx
@@ -482,6 +482,7 @@ function ServerGate(props: { children: (data: ServerReadyData) => JSX.Element })
return (
@@ -489,7 +490,7 @@ function ServerGate(props: { children: (data: ServerReadyData) => JSX.Element })
}
>
- {(data) => props.children(data())}
+ {(data) => props.children(data)}
)
}