Compare commits

...

1 Commits

Author SHA1 Message Date
thdxr b99615bd93 fix(tui): rank sessions before settings for /se 2026-08-26 19:31:47 +00:00
2 changed files with 57 additions and 1 deletions
@@ -628,12 +628,16 @@ export function Autocomplete(props: {
let score = objResults.score
const prefix = store.visible === "reference" ? "@" : store.visible === "command" ? "/" : ""
if (displayResult && displayResult.target.startsWith(prefix + searchValue)) {
score *= 2
// Descriptions should not reorder equally matching command names.
score = (store.visible === "command" ? displayResult.score : score) * 2
}
const frecencyScore = objResults.obj.path ? frecency.getFrecency(objResults.obj.path) : 0
return score * (1 + frecencyScore)
},
})
.toSorted(
(a, b) => b.score - a.score || (store.visible === "command" ? a.obj.display.localeCompare(b.obj.display) : 0),
)
.map((arr) => arr.obj)
return [...fuzziedNonFiles, ...fileOptions].slice(0, 10)
+52
View File
@@ -707,6 +707,58 @@ test("configured app bindings execute settings and permission commands", async (
}
})
test("slash autocomplete ranks command prefixes before descriptions", async () => {
const setup = await createTestRenderer({ width: 100, height: 30, useThread: false, kittyKeyboard: true })
setup.renderer.start()
const ready = Promise.withResolvers<void>()
const calls = createFetch(undefined, createEventStream())
const server = Bun.serve({ port: 0, fetch: (request) => calls.fetch(request) })
try {
const { run } = await import("../src/app")
const task = Effect.runPromise(
run({
app: { name: "test", version: "test", channel: "test" },
server: { endpoint: { url: server.url.toString() } },
config: { get: async () => ({ animations: false }), update: async () => ({}) },
packages: { resolve: async () => undefined },
args: {},
terminalHandoff: async () => ({ renderer: setup.renderer, mode: "dark", complete: ready.resolve }),
log: () => {},
}).pipe(Effect.provide(AppNodeBuilder.build(Global.node)), Effect.provide(FileSystem.layerNoop({}))),
)
await ready.promise
await setup.waitForFrame((frame) => frame.includes("commands"))
for (const [query, expected] of [
["se", "/sessions"],
["ses", "/sessions"],
["set", "/settings"],
["settings", "/settings"],
["resume", "/sessions"],
["continue", "/sessions"],
["switch", "/agents"],
]) {
await setup.mockInput.typeText(`/${query}`)
await setup.waitForFrame((frame) => frame.includes("Switch session") || frame.includes("Open settings"))
expect(setup.captureCharFrame().match(/(\/[\w-]+) {2,}\S/)?.[1]).toBe(expected)
setup.mockInput.pressKey("c", { ctrl: true })
await setup.waitForFrame((frame) => !frame.includes("Switch session") && !frame.includes("Open settings"))
}
await setup.mockInput.typeText("/se")
await setup.waitForFrame((frame) => frame.includes("Switch session"))
setup.mockInput.pressEnter()
await setup.waitForFrame((frame) => frame.includes("Sessions") && !frame.includes("Open settings"))
setup.renderer.destroy()
await task
} finally {
if (!setup.renderer.isDestroyed) setup.renderer.destroy()
await server.stop()
}
})
test("ctrl+c dismisses autocomplete and shell mode before exiting", async () => {
const setup = await createTestRenderer({ width: 100, height: 30, useThread: false, kittyKeyboard: true })
setup.renderer.start()