mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-13 15:03:43 -04:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b2c0cbf323 | |||
| 3c2005a244 | |||
| 2f92b3762a | |||
| 30b977880c |
@@ -103,7 +103,7 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
|
||||
const base = pickerRoot(cleaned) || root() || start()
|
||||
if (!base) return { query: value, items: directories.slice(0, 5) }
|
||||
const files = await sdk.api.file
|
||||
.find({
|
||||
.get({
|
||||
location: { directory: base },
|
||||
query: pickerFileSearchQuery(base, value, home()),
|
||||
type: "file",
|
||||
|
||||
@@ -135,7 +135,7 @@ test("resolves directory autocomplete from the current browser root", async () =
|
||||
const sdk = {
|
||||
api: {
|
||||
file: {
|
||||
find: (input: { location?: { directory?: string } }) => {
|
||||
get: (input: { location?: { directory?: string } }) => {
|
||||
directories.push(input.location?.directory ?? "")
|
||||
return Promise.resolve({ data: [] })
|
||||
},
|
||||
@@ -157,7 +157,7 @@ test("keeps indexed directory results for servers that support empty search", as
|
||||
const sdk = {
|
||||
api: {
|
||||
file: {
|
||||
find: () => Promise.resolve({ data: [{ path: "projects/", type: "directory" }] }),
|
||||
get: () => Promise.resolve({ data: [{ path: "projects/", type: "directory" }] }),
|
||||
list: () => Promise.reject(new Error("listing should not run when search returns results")),
|
||||
},
|
||||
},
|
||||
@@ -176,7 +176,7 @@ test("lists the default directory when empty search is unsupported", async () =>
|
||||
const sdk = {
|
||||
api: {
|
||||
file: {
|
||||
find: () => Promise.resolve({ data: [] }),
|
||||
get: () => Promise.resolve({ data: [] }),
|
||||
list: (input: { location?: { directory?: string } }) => {
|
||||
calls.push(input.location?.directory ?? "")
|
||||
return Promise.resolve({
|
||||
@@ -198,7 +198,7 @@ test("matches the default directory listing when typed search is unsupported", a
|
||||
const sdk = {
|
||||
api: {
|
||||
file: {
|
||||
find: () => Promise.resolve({ data: [] }),
|
||||
get: () => Promise.resolve({ data: [] }),
|
||||
list: () =>
|
||||
Promise.resolve({
|
||||
data: [
|
||||
|
||||
@@ -375,7 +375,7 @@ export function createDirectorySearch(args: { sdk: ServerSDK; base: () => string
|
||||
const query = normalizePickerDrive(input.path)
|
||||
if (!pathInput) {
|
||||
const results = await args.sdk.api.file
|
||||
.find({ location: { directory: input.directory }, query, type: "directory", limit: 50 })
|
||||
.get({ location: { directory: input.directory }, query, type: "directory", limit: 50 })
|
||||
.then((result) => result.data.map((entry) => entry.path))
|
||||
.catch(() => [])
|
||||
if (!active()) return []
|
||||
|
||||
@@ -212,7 +212,7 @@ export const { use: useFile, provider: FileProvider } = createSimpleContext({
|
||||
|
||||
const search = (query: string, dirs: "true" | "false", options?: { limit?: number; signal?: AbortSignal }) =>
|
||||
serverSDK()
|
||||
.api.file.find(
|
||||
.api.file.get(
|
||||
{
|
||||
location: { directory: sdk().directory },
|
||||
query,
|
||||
|
||||
@@ -1362,11 +1362,11 @@ export type Endpoint16_1Input = {
|
||||
readonly limit?: number | undefined
|
||||
}
|
||||
export type Endpoint16_1Output = { readonly location: Location.Info; readonly data: ReadonlyArray<FileSystem.Entry> }
|
||||
export type FileFindOperation<E = never> = (input: Endpoint16_1Input) => Effect.Effect<Endpoint16_1Output, E>
|
||||
export type FileGetOperation<E = never> = (input: Endpoint16_1Input) => Effect.Effect<Endpoint16_1Output, E>
|
||||
|
||||
export interface FileApi<E = never> {
|
||||
readonly list: FileListOperation<E>
|
||||
readonly find: FileFindOperation<E>
|
||||
readonly get: FileGetOperation<E>
|
||||
}
|
||||
|
||||
export type Endpoint17_0Input = {
|
||||
|
||||
@@ -1034,12 +1034,12 @@ const Endpoint16_0 = (raw: RawClient["server.fs"]) => (input?: Endpoint16_0Input
|
||||
|
||||
const Endpoint16_1 = (raw: RawClient["server.fs"]) => (input: Endpoint16_1Input) =>
|
||||
preserveEffect<Endpoint16_1Output>()(
|
||||
raw["fs.find"]({
|
||||
raw["fs.get"]({
|
||||
query: { location: input["location"], query: input["query"], type: input["type"], limit: input["limit"] },
|
||||
}).pipe(Effect.mapError(mapClientError)),
|
||||
)
|
||||
|
||||
const adaptGroup16 = (raw: RawClient["server.fs"]) => ({ list: Endpoint16_0(raw), find: Endpoint16_1(raw) })
|
||||
const adaptGroup16 = (raw: RawClient["server.fs"]) => ({ list: Endpoint16_0(raw), get: Endpoint16_1(raw) })
|
||||
|
||||
const Endpoint17_0 = (raw: RawClient["server.command"]) => (input?: Endpoint17_0Input) =>
|
||||
preserveEffect<Endpoint17_0Output>()(
|
||||
|
||||
@@ -167,8 +167,8 @@ import type {
|
||||
FileReadOutput,
|
||||
FileListInput,
|
||||
FileListOutput,
|
||||
FileFindInput,
|
||||
FileFindOutput,
|
||||
FileGetInput,
|
||||
FileGetOutput,
|
||||
CommandListInput,
|
||||
CommandListOutput,
|
||||
SkillListInput,
|
||||
@@ -1473,8 +1473,8 @@ export function make(options: ClientOptions) {
|
||||
},
|
||||
requestOptions,
|
||||
),
|
||||
find: (input: FileFindInput, requestOptions?: RequestOptions) =>
|
||||
request<FileFindOutput>(
|
||||
get: (input: FileGetInput, requestOptions?: RequestOptions) =>
|
||||
request<FileGetOutput>(
|
||||
{
|
||||
method: "GET",
|
||||
path: `/api/fs/find`,
|
||||
|
||||
@@ -5335,7 +5335,7 @@ export type FileListOutput = {
|
||||
data: Array<FileSystemEntry>
|
||||
}
|
||||
|
||||
export type FileFindInput = {
|
||||
export type FileGetInput = {
|
||||
readonly location?: {
|
||||
readonly location?: { readonly directory?: string | undefined; readonly workspace?: string | undefined } | undefined
|
||||
readonly query: string
|
||||
@@ -5362,7 +5362,7 @@ export type FileFindInput = {
|
||||
}["limit"]
|
||||
}
|
||||
|
||||
export type FileFindOutput = {
|
||||
export type FileGetOutput = {
|
||||
location: { directory: string; workspaceID?: string; project: { id: string; directory: string; canonical: string } }
|
||||
data: Array<FileSystemEntry>
|
||||
}
|
||||
|
||||
@@ -6866,7 +6866,7 @@
|
||||
"/api/fs/find": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
"operationId": "v2.fs.find",
|
||||
"operationId": "v2.fs.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
|
||||
@@ -8534,7 +8534,7 @@
|
||||
"/api/fs/find": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
"operationId": "v2.fs.find",
|
||||
"operationId": "v2.fs.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
|
||||
@@ -47,14 +47,14 @@ export const FileSystemGroup = HttpApiGroup.make("server.fs")
|
||||
),
|
||||
)
|
||||
.add(
|
||||
HttpApiEndpoint.get("fs.find", "/api/fs/find", {
|
||||
HttpApiEndpoint.get("fs.get", "/api/fs/find", {
|
||||
query: FindQuery,
|
||||
success: Location.response(Schema.Array(FileSystem.Entry)),
|
||||
})
|
||||
.annotateMerge(locationQueryOpenApi)
|
||||
.annotateMerge(
|
||||
OpenApi.annotations({
|
||||
identifier: "v2.fs.find",
|
||||
identifier: "v2.fs.get",
|
||||
summary: "Find files",
|
||||
description: "Find recursively ranked filesystem entries relative to the requested location.",
|
||||
}),
|
||||
|
||||
@@ -28,7 +28,7 @@ export const FileSystemHandler = HttpApiBuilder.group(Api, "server.fs", (handler
|
||||
}),
|
||||
),
|
||||
)
|
||||
.handle("fs.find", (ctx) =>
|
||||
.handle("fs.get", (ctx) =>
|
||||
response(
|
||||
Effect.gen(function* () {
|
||||
const fs = yield* FileSystem.Service
|
||||
|
||||
@@ -227,8 +227,9 @@ export function DialogSessionList() {
|
||||
</box>
|
||||
}
|
||||
onMove={() => setToDelete(undefined)}
|
||||
onSelect={(option) => {
|
||||
route.navigate({ type: "session", sessionID: option.value })
|
||||
onSelect={(option, activation) => {
|
||||
if (activation.shift) route.navigate({ type: "session", sessionID: option.value })
|
||||
else sessionTabs.replace(option.value)
|
||||
dialog.clear()
|
||||
}}
|
||||
actions={[
|
||||
|
||||
@@ -353,7 +353,7 @@ export function Autocomplete(props: {
|
||||
const result = await (
|
||||
input.visible === "directory"
|
||||
? client.api.file.list({ location: requestLocation })
|
||||
: client.api.file.find({ query: base, limit: 20, location: requestLocation })
|
||||
: client.api.file.get({ query: base, limit: 20, location: requestLocation })
|
||||
).then(
|
||||
(result) => result,
|
||||
() => undefined,
|
||||
|
||||
@@ -241,7 +241,7 @@ export const Definitions = {
|
||||
"dialog.select.page_down": keybind("pagedown", "Move down one page in dialog"),
|
||||
"dialog.select.home": keybind("home", "Move to first dialog item"),
|
||||
"dialog.select.end": keybind("end", "Move to last dialog item"),
|
||||
"dialog.select.submit": keybind("return", "Submit selected dialog item"),
|
||||
"dialog.select.submit": keybind("return,shift+return,linefeed", "Submit selected dialog item"),
|
||||
"dialog.prompt.submit": keybind("return", "Submit dialog prompt"),
|
||||
"dialog.project_copy.generate": keybind("tab", "Generate project copy name"),
|
||||
"dialog.move_session.new": keybind("ctrl+m", "New project copy"),
|
||||
|
||||
@@ -218,7 +218,7 @@ export const Definitions = {
|
||||
"dialog.select.page_down": keybind("pagedown", "Move down one page in dialog"),
|
||||
"dialog.select.home": keybind("home", "Move to first dialog item"),
|
||||
"dialog.select.end": keybind("end", "Move to last dialog item"),
|
||||
"dialog.select.submit": keybind("return", "Submit selected dialog item"),
|
||||
"dialog.select.submit": keybind("return,shift+return,linefeed", "Submit selected dialog item"),
|
||||
"dialog.prompt.submit": keybind("return", "Submit dialog prompt"),
|
||||
"dialog.project_copy.generate": keybind("tab", "Generate project copy name"),
|
||||
"dialog.move_session.new": keybind("ctrl+m", "New project copy"),
|
||||
|
||||
@@ -35,6 +35,13 @@ export function openSessionTab(tabs: SessionTab[], tab: SessionTab): SessionTab[
|
||||
return tabs.map((item, position) => (position === index ? { ...item, title: tab.title } : item))
|
||||
}
|
||||
|
||||
export function replaceSessionTab(tabs: SessionTab[], current: string | undefined, tab: SessionTab): SessionTab[] {
|
||||
if (tabs.some((item) => item.sessionID === tab.sessionID)) return tabs
|
||||
const index = current ? tabs.findIndex((item) => item.sessionID === current) : -1
|
||||
if (index === -1) return [...tabs, tab]
|
||||
return tabs.map((item, position) => (position === index ? tab : item))
|
||||
}
|
||||
|
||||
export function closeSessionTab(tabs: SessionTab[], sessionID: string) {
|
||||
const index = tabs.findIndex((tab) => tab.sessionID === sessionID)
|
||||
// Like openSessionTab and moveSessionTab, a no-op returns the same reference so callers can
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
openSessionTab,
|
||||
recordClosedSessionTab,
|
||||
recordSessionTabHistory,
|
||||
replaceSessionTab,
|
||||
reopenSessionTab,
|
||||
type ClosedSessionTab,
|
||||
type SessionTab,
|
||||
@@ -64,6 +65,7 @@ export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimp
|
||||
const fallback = empty()
|
||||
const [promptPulses, setPromptPulses] = createSignal<Record<string, number>>({})
|
||||
let history: SessionTabHistory = { entries: [], index: -1 }
|
||||
let replacement: string | undefined
|
||||
// User-closed tabs eligible for reopening; in-memory like history, deleted sessions pruned.
|
||||
let closedTabs: ClosedSessionTab[] = []
|
||||
|
||||
@@ -132,18 +134,22 @@ export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimp
|
||||
if (!enabled()) return
|
||||
if (route.data.type !== "session" || route.data.sessionID === "dummy") return
|
||||
const sessionID = root(route.data.sessionID)
|
||||
const replaced = replacement
|
||||
replacement = undefined
|
||||
history = recordSessionTabHistory(history, sessionID)
|
||||
const fallback = newTab() ? NEW_SESSION_TAB_TITLE : undefined
|
||||
const tabs = openSessionTab(state().tabs, {
|
||||
const fallback = !replaced && newTab() ? NEW_SESSION_TAB_TITLE : undefined
|
||||
const tab = {
|
||||
sessionID,
|
||||
title: title(sessionID, state().tabs.find((tab) => tab.sessionID === sessionID)?.title, fallback),
|
||||
})
|
||||
}
|
||||
const tabs = replaced ? replaceSessionTab(state().tabs, replaced, tab) : openSessionTab(state().tabs, tab)
|
||||
if (tabs === state().tabs && !state().unread[sessionID]) return
|
||||
update((draft) => {
|
||||
draft.tabs = openSessionTab(draft.tabs, {
|
||||
const tab = {
|
||||
sessionID,
|
||||
title: title(sessionID, draft.tabs.find((tab) => tab.sessionID === sessionID)?.title, fallback),
|
||||
})
|
||||
}
|
||||
draft.tabs = replaced ? replaceSessionTab(draft.tabs, replaced, tab) : openSessionTab(draft.tabs, tab)
|
||||
delete draft.unread[sessionID]
|
||||
})
|
||||
})
|
||||
@@ -251,6 +257,16 @@ export const { use: useSessionTabs, provider: SessionTabsProvider } = createSimp
|
||||
if (!enabled()) return
|
||||
route.navigate({ type: "session", sessionID: root(sessionID) })
|
||||
},
|
||||
replace(sessionID: string) {
|
||||
const target = root(sessionID)
|
||||
if (!enabled()) {
|
||||
route.navigate({ type: "session", sessionID: target })
|
||||
return
|
||||
}
|
||||
if (target === current()) return
|
||||
replacement = current()
|
||||
route.navigate({ type: "session", sessionID: target })
|
||||
},
|
||||
add() {
|
||||
if (!enabled()) return
|
||||
const sessionID = current()
|
||||
|
||||
@@ -235,7 +235,7 @@ async function runInteractiveRuntime(input: RunRuntimeInput, deps: RunRuntimeDep
|
||||
getDirectory: () => state.location.directory,
|
||||
findFiles: (query) =>
|
||||
state.sdk.file
|
||||
.find({
|
||||
.get({
|
||||
query,
|
||||
type: "file",
|
||||
location: { directory: state.location.directory, workspace: state.location.workspaceID },
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
import { CliRenderEvents, InputRenderable, RGBA, ScrollBoxRenderable, TextAttributes } from "@opentui/core"
|
||||
import {
|
||||
CliRenderEvents,
|
||||
InputRenderable,
|
||||
RGBA,
|
||||
ScrollBoxRenderable,
|
||||
TextAttributes,
|
||||
type KeyEvent,
|
||||
} from "@opentui/core"
|
||||
import { Keymap, type KeymapCommand } from "../context/keymap"
|
||||
import { useTheme, useThemes } from "../context/theme"
|
||||
import { entries, filter, flatMap, groupBy, pipe } from "remeda"
|
||||
@@ -26,7 +33,7 @@ export interface DialogSelectProps<T> {
|
||||
ref?: (ref: DialogSelectRef<T>) => void
|
||||
onMove?: (option: DialogSelectOption<T>) => void
|
||||
onFilter?: (query: string) => void
|
||||
onSelect?: (option: DialogSelectOption<T>) => void
|
||||
onSelect?: (option: DialogSelectOption<T>, activation: { shift: boolean }) => void
|
||||
skipFilter?: boolean
|
||||
renderFilter?: boolean
|
||||
locked?: boolean
|
||||
@@ -382,7 +389,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
||||
}
|
||||
}
|
||||
|
||||
function submit() {
|
||||
function submit(_input?: string, event?: KeyEvent) {
|
||||
if (props.locked) return
|
||||
setStore("input", "keyboard")
|
||||
const index = focusedAction()
|
||||
@@ -393,7 +400,7 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
||||
const option = selected()
|
||||
if (!option) return
|
||||
option.onSelect?.(dialog)
|
||||
props.onSelect?.(option)
|
||||
props.onSelect?.(option, { shift: event?.shift === true || event?.name === "linefeed" })
|
||||
}
|
||||
|
||||
function moveAction(direction: 1 | -1) {
|
||||
@@ -712,10 +719,10 @@ export function DialogSelect<T>(props: DialogSelectProps<T>) {
|
||||
setStore("input", "mouse")
|
||||
setFocusedAction(undefined)
|
||||
}}
|
||||
onMouseUp={() => {
|
||||
onMouseUp={(event) => {
|
||||
if (props.locked) return
|
||||
option.onSelect?.(dialog)
|
||||
props.onSelect?.(option)
|
||||
props.onSelect?.(option, { shift: event.modifiers.shift })
|
||||
}}
|
||||
onMouseOver={() => {
|
||||
if (props.locked) return
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/** @jsxImportSource @opentui/solid */
|
||||
import { InputRenderable } from "@opentui/core"
|
||||
import { MouseButtons } from "@opentui/core/testing"
|
||||
import { testRender } from "@opentui/solid"
|
||||
import { expect, test } from "bun:test"
|
||||
import { mkdir } from "node:fs/promises"
|
||||
@@ -109,6 +110,7 @@ async function mountSelect(
|
||||
])
|
||||
|
||||
const selected: string[] = []
|
||||
const shifted: boolean[] = []
|
||||
const moved: string[] = []
|
||||
let replaceOptions!: (options: DialogSelectOption<string>[]) => void
|
||||
|
||||
@@ -127,7 +129,10 @@ async function mountSelect(
|
||||
focusCurrent={focusCurrent}
|
||||
flat={select?.flat}
|
||||
onMove={(option) => moved.push(option.value)}
|
||||
onSelect={(option) => selected.push(option.value)}
|
||||
onSelect={(option, activation) => {
|
||||
selected.push(option.value)
|
||||
shifted.push(activation.shift)
|
||||
}}
|
||||
/>
|
||||
)),
|
||||
)
|
||||
@@ -155,9 +160,49 @@ async function mountSelect(
|
||||
app.renderer.start()
|
||||
await app.waitForFrame((frame) => frame.includes("Mutable options"))
|
||||
await app.waitFor(() => app.renderer.currentFocusedEditor instanceof InputRenderable)
|
||||
return { app, moved, replaceOptions, selected }
|
||||
return { app, moved, replaceOptions, selected, shifted }
|
||||
}
|
||||
|
||||
test("reports Shift for keyboard selection", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
const select = await mountSelect(tmp.path, [{ title: "Alpha", value: "alpha" }])
|
||||
|
||||
try {
|
||||
select.app.mockInput.pressEnter({ shift: true })
|
||||
expect(select.selected).toEqual(["alpha"])
|
||||
expect(select.shifted).toEqual([true])
|
||||
} finally {
|
||||
select.app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("treats a raw linefeed as Shift selection", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
const select = await mountSelect(tmp.path, [{ title: "Alpha", value: "alpha" }])
|
||||
|
||||
try {
|
||||
select.app.renderer.stdin.emit("data", Buffer.from("\n"))
|
||||
await select.app.waitFor(() => select.selected.length === 1)
|
||||
expect(select.selected).toEqual(["alpha"])
|
||||
expect(select.shifted).toEqual([true])
|
||||
} finally {
|
||||
select.app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("reports Shift for mouse selection", async () => {
|
||||
await using tmp = await tmpdir()
|
||||
const select = await mountSelect(tmp.path, [{ title: "Alpha", value: "alpha" }])
|
||||
|
||||
try {
|
||||
await select.app.mockMouse.click(15, 11, MouseButtons.LEFT, { modifiers: { shift: true } })
|
||||
expect(select.selected).toEqual(["alpha"])
|
||||
expect(select.shifted).toEqual([true])
|
||||
} finally {
|
||||
select.app.renderer.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("budgets option content for constrained and full-width large dialogs", () => {
|
||||
expect(dialogSelectContentWidth(Math.min(dialogWidth("large"), 62 - 2)) - 7).toBe(41)
|
||||
expect(dialogSelectContentWidth(Math.min(dialogWidth("large"), 100 - 2)) - 7).toBe(69)
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
recordClosedSessionTab,
|
||||
recordSessionTabHistory,
|
||||
reopenSessionTab,
|
||||
replaceSessionTab,
|
||||
seedSessionTabMotion,
|
||||
sessionTabComplete,
|
||||
sessionTabOverflowWidth,
|
||||
@@ -89,6 +90,18 @@ describe("session tabs", () => {
|
||||
expect(openSessionTab(tabs, { sessionID: "a", title: "New" })).toBe(tabs)
|
||||
})
|
||||
|
||||
test("replaces the active tab without duplicating an already-open target", () => {
|
||||
const tabs = ["a", "b", "c"].map((sessionID) => ({ sessionID }))
|
||||
expect(replaceSessionTab(tabs, "b", { sessionID: "d" }).map((tab) => tab.sessionID)).toEqual(["a", "d", "c"])
|
||||
expect(replaceSessionTab(tabs, "b", { sessionID: "c" })).toBe(tabs)
|
||||
expect(replaceSessionTab(tabs, undefined, { sessionID: "d" }).map((tab) => tab.sessionID)).toEqual([
|
||||
"a",
|
||||
"b",
|
||||
"c",
|
||||
"d",
|
||||
])
|
||||
})
|
||||
|
||||
test("selects the right tab then the left tab after closing", () => {
|
||||
expect(closeSessionTab([{ sessionID: "a" }, { sessionID: "b" }, { sessionID: "c" }], "b")).toEqual({
|
||||
tabs: [{ sessionID: "a" }, { sessionID: "c" }],
|
||||
|
||||
@@ -289,3 +289,25 @@ test("add opens the new session tab carrying the current session's location", as
|
||||
await setup.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
test("replace swaps the current tab while selecting an existing tab preserves the tab list", async () => {
|
||||
const setup = await renderSessionTabs("first")
|
||||
|
||||
try {
|
||||
await wait(() => setup.tabs.current() === "first")
|
||||
setup.route.navigate({ type: "session", sessionID: "second" })
|
||||
await wait(() => setup.tabs.current() === "second" && setup.tabs.tabs().length === 2)
|
||||
|
||||
setup.tabs.replace("third")
|
||||
await wait(
|
||||
() => setup.tabs.current() === "third" && setup.tabs.tabs().map((tab) => tab.sessionID).join() === "first,third",
|
||||
)
|
||||
expect(setup.tabs.tabs().map((tab) => tab.sessionID)).toEqual(["first", "third"])
|
||||
|
||||
setup.tabs.replace("first")
|
||||
await wait(() => setup.tabs.current() === "first")
|
||||
expect(setup.tabs.tabs().map((tab) => tab.sessionID)).toEqual(["first", "third"])
|
||||
} finally {
|
||||
await setup.destroy()
|
||||
}
|
||||
})
|
||||
|
||||
@@ -504,7 +504,7 @@ describe("run interactive runtime", () => {
|
||||
const catalogs = stubCatalogLists(sdk, {
|
||||
location: { directory: "/session", workspaceID: "work-1" },
|
||||
})
|
||||
const fileFind = spyOn(sdk.file, "find").mockResolvedValue({
|
||||
const fileGet = spyOn(sdk.file, "get").mockResolvedValue({
|
||||
location: {
|
||||
directory: "/session",
|
||||
workspaceID: "work-1",
|
||||
@@ -591,6 +591,6 @@ describe("run interactive runtime", () => {
|
||||
expect(catalogs.reference).toHaveBeenCalledWith(query, { signal: expect.any(AbortSignal) })
|
||||
expect(catalogs.command).toHaveBeenCalledWith(query, { signal: expect.any(AbortSignal) })
|
||||
expect(catalogs.skill).toHaveBeenCalledWith(query, { signal: expect.any(AbortSignal) })
|
||||
expect(fileFind).toHaveBeenCalledWith({ query: "index", type: "file", ...query })
|
||||
expect(fileGet).toHaveBeenCalledWith({ query: "index", type: "file", ...query })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -8534,7 +8534,7 @@
|
||||
"/api/fs/find": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
"operationId": "v2.fs.find",
|
||||
"operationId": "v2.fs.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
|
||||
@@ -8534,7 +8534,7 @@
|
||||
"/api/fs/find": {
|
||||
"get": {
|
||||
"tags": ["filesystem"],
|
||||
"operationId": "v2.fs.find",
|
||||
"operationId": "v2.fs.get",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "location",
|
||||
|
||||
Reference in New Issue
Block a user