Forráskód Böngészése

fix(tui): open sessions by exact ID (#41180)

Kit Langton 1 hete
szülő
commit
fd09760903

+ 14 - 1
packages/tui/src/component/dialog-open.tsx

@@ -51,6 +51,17 @@ export function DialogOpen() {
         .catch(() => [] as SessionInfo[]),
     { initialValue: [] },
   )
+  const [matched] = createResource(
+    () => {
+      const value = filter().trim()
+      return /^ses_[0-9A-Za-z]{26}$/.test(value) ? value : undefined
+    },
+    (sessionID) =>
+      client.api.session
+        .get({ sessionID })
+        .then((session) => (session.id === sessionID ? session : undefined))
+        .catch(() => undefined),
+  )
 
   const openTabs = createMemo(
     () => new Set(sessionTabs.enabled() ? sessionTabs.tabs().map((tab) => tab.sessionID) : []),
@@ -60,7 +71,8 @@ export function DialogOpen() {
   )
   const sessions = createMemo(() => {
     const seen = new Set<string>()
-    return [...data.session.list(), ...fetched()]
+    const match = matched()
+    return [...data.session.list(), ...fetched(), ...(match ? [match] : [])]
       .filter((session) => {
         if (session.parentID || seen.has(session.id)) return false
         seen.add(session.id)
@@ -87,6 +99,7 @@ export function DialogOpen() {
         data.session.family(session.id).some((id) => data.session.status(id) === "running")
       return {
         title: withTimestampedFallback(session),
+        searchText: session.id,
         value: { type: "session", sessionID: session.id } as OpenTarget,
         category: "Sessions",
         footer: `${name ? `${Locale.truncate(name, 20)} · ` : ""}${timeAgo(session.time.updated)}`,

+ 34 - 0
packages/tui/test/cli/tui/dialog-open.test.tsx

@@ -54,6 +54,40 @@ test("selecting an unhydrated session preserves its location", async () => {
   }
 })
 
+test("finds and opens an exact session ID outside the recent list", async () => {
+  const sessionID = "ses_04a7a3d82ffeIphUJgd3SnEqiv"
+  const remote = { directory: "/tmp/opencode/archive", workspaceID: "ws_archive" }
+  const fixture = await renderOpen((url) => {
+    if (url.pathname === "/api/session") return json({ data: [], cursor: {} })
+    if (url.pathname !== `/api/session/${sessionID}`) return undefined
+    return json({
+      data: {
+        id: sessionID,
+        projectID: "proj_archive",
+        cost: 0,
+        tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 } },
+        time: { created: 1, updated: 2 },
+        title: "TUI plugin slot API v2",
+        location: remote,
+      },
+    })
+  })
+
+  try {
+    await fixture.app.waitForFrame((frame) => frame.includes("Search sessions and projects"))
+    await fixture.app.mockInput.typeText(sessionID)
+    await fixture.app.waitForFrame((frame) => frame.includes("TUI plugin slot API v2"))
+
+    fixture.app.mockInput.pressEnter()
+    await fixture.app.waitFor(() => fixture.route.data.type === "session")
+
+    expect(fixture.route.data).toEqual({ type: "session", sessionID })
+    expect(fixture.location.ref).toEqual(remote)
+  } finally {
+    fixture.dispose()
+  }
+})
+
 test("shows the current project and opens its root", async () => {
   const root = "/tmp/opencode/project"
   const subfolder = `${root}/packages/tui`