opencode-agent[bot] пре 2 месеци
родитељ
комит
1c2c2d6b52

+ 1 - 1
bun.lock

@@ -914,6 +914,7 @@
   ],
   "patchedDependencies": {
     "solid-js@1.9.10": "patches/solid-js@1.9.10.patch",
+    "@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
     "virtua@0.49.1": "patches/virtua@0.49.1.patch",
     "@modelcontextprotocol/sdk@1.29.0": "patches/@modelcontextprotocol%2Fsdk@1.29.0.patch",
     "gcp-metadata@8.1.2": "patches/gcp-metadata@8.1.2.patch",
@@ -923,7 +924,6 @@
     "pacote@21.5.0": "patches/pacote@21.5.0.patch",
     "@npmcli/agent@4.0.2": "patches/@npmcli%2Fagent@4.0.2.patch",
     "@silvia-odwyer/photon-node@0.3.4": "patches/@silvia-odwyer%2Fphoton-node@0.3.4.patch",
-    "@pierre/trees@1.0.0-beta.4": "patches/@pierre%2Ftrees@1.0.0-beta.4.patch",
   },
   "overrides": {
     "@opentui/core": "catalog:",

+ 33 - 17
packages/app/src/components/dialog-select-directory-v2.tsx

@@ -64,12 +64,21 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
   const missingBase = createMemo(() => !(sync.data.path.home || sync.data.path.directory))
   const [fallbackPath] = createResource(
     () => (missingBase() ? true : undefined),
-    () => sdk.client.path.get().then((result) => result.data).catch(() => undefined),
+    () =>
+      sdk.client.path
+        .get()
+        .then((result) => result.data)
+        .catch(() => undefined),
     { initialValue: undefined },
   )
   const home = createMemo(() => sync.data.path.home || fallbackPath()?.home || "")
   const start = createMemo(
-    () => props.start || sync.data.path.home || sync.data.path.directory || fallbackPath()?.home || fallbackPath()?.directory,
+    () =>
+      props.start ||
+      sync.data.path.home ||
+      sync.data.path.directory ||
+      fallbackPath()?.home ||
+      fallbackPath()?.directory,
   )
   const search = createDirectorySearch({ sdk, home, base: () => root() || start() })
   const [suggestions] = createResource(input, async (value) => {
@@ -111,9 +120,7 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
       if (!key) setError(true)
       return false
     }
-    tree?.batch(
-      policy.entries(key, nodes).map((item) => ({ type: "add", path: item })),
-    )
+    tree?.batch(policy.entries(key, nodes).map((item) => ({ type: "add", path: item })))
     if (preload && advanceTreePreload(advanced, key)) {
       void Promise.all(preloadTreeDirectories(key, nodes).map((directory) => load(directory, generation, false)))
     }
@@ -147,9 +154,7 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
     const value = displayPickerPath(match.absolute, input(), home())
     setInput(match.type === "directory" && !value.endsWith("/") ? value + "/" : value)
     if (match.type === "file") {
-      setSelected(
-        policy.selection(root(), pickerFileSearchQuery(root(), match.absolute, home())) ?? "",
-      )
+      setSelected(policy.selection(root(), pickerFileSearchQuery(root(), match.absolute, home())) ?? "")
       setSuggestionsOpen(false)
       setActiveSuggestion(-1)
     }
@@ -161,9 +166,7 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
       return
     }
     setInput(displayPickerPath(suggestion.absolute, input(), home()))
-    setSelected(
-      policy.selection(root(), pickerFileSearchQuery(root(), suggestion.absolute, home())) ?? "",
-    )
+    setSelected(policy.selection(root(), pickerFileSearchQuery(root(), suggestion.absolute, home())) ?? "")
     setSuggestionsOpen(false)
     setActiveSuggestion(-1)
   }
@@ -239,7 +242,7 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
       },
       onSelectionChange(paths) {
         const path = paths.at(-1)
-        setSelected(path ? policy.selection(root(), path) ?? "" : "")
+        setSelected(path ? (policy.selection(root(), path) ?? "") : "")
       },
     })
     if (!container) return
@@ -275,11 +278,15 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
             aria-autocomplete="list"
             aria-expanded={suggestionsOpen()}
             aria-controls="directory-picker-v2-suggestions"
-            aria-activedescendant={activeSuggestion() >= 0 ? `directory-picker-v2-suggestion-${activeSuggestion()}` : undefined}
+            aria-activedescendant={
+              activeSuggestion() >= 0 ? `directory-picker-v2-suggestion-${activeSuggestion()}` : undefined
+            }
             onKeyDown={handleInputKey}
           />
           <div class="directory-picker-v2-actions">
-            <ButtonV2 size="small" variant="ghost" onClick={() => void navigate(home())}>~</ButtonV2>
+            <ButtonV2 size="small" variant="ghost" onClick={() => void navigate(home())}>
+              ~
+            </ButtonV2>
             <ButtonV2 size="small" variant="ghost" onClick={() => void navigate(pickerRoot(root()) || root())}>
               {language.t("dialog.directory.root")}
             </ButtonV2>
@@ -315,14 +322,21 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
               ?.getFileTreeContainer()
               ?.shadowRoot?.querySelector<HTMLElement>("[data-file-tree-virtualized-scroll]")
             if (!scroller) return
-            const next = nextTreeScrollTop(scroller.scrollTop, event.deltaY, scroller.scrollHeight, scroller.clientHeight)
+            const next = nextTreeScrollTop(
+              scroller.scrollTop,
+              event.deltaY,
+              scroller.scrollHeight,
+              scroller.clientHeight,
+            )
             if (next === scroller.scrollTop) return
             event.preventDefault()
             scroller.scrollTop = next
             scroller.dispatchEvent(new Event("scroll"))
           }}
         >
-          <Show when={loading()}><div class="directory-picker-v2-state">{language.t("common.loading")}</div></Show>
+          <Show when={loading()}>
+            <div class="directory-picker-v2-state">{language.t("common.loading")}</div>
+          </Show>
           <Show when={!loading() && error()}>
             <div class="directory-picker-v2-state">{language.t("dialog.directory.readError")}</div>
           </Show>
@@ -330,7 +344,9 @@ export function DialogSelectDirectoryV2(props: DialogSelectDirectoryV2Props) {
         <div class="directory-picker-v2-selection">{policy.result(root(), selected(), rootValid())}</div>
       </div>
       <DialogFooter>
-        <ButtonV2 variant="neutral" onClick={() => dialog.close()}>{language.t("common.cancel")}</ButtonV2>
+        <ButtonV2 variant="neutral" onClick={() => dialog.close()}>
+          {language.t("common.cancel")}
+        </ButtonV2>
         <ButtonV2 variant="contrast" disabled={!policy.result(root(), selected(), rootValid())} onClick={resolve}>
           {action[policy.action]}
         </ButtonV2>

+ 1 - 3
packages/app/src/components/directory-picker-domain.test.ts

@@ -86,9 +86,7 @@ test("preserves POSIX case while matching Windows drives case-insensitively", ()
   expect(treePathWithin("/repo", "/Repo")).toBeFalse()
   expect(treePathWithin("C:/Repo", "c:/repo/src")).toBeTrue()
   expect(treePathWithin("//Server/Share/Repo", "//server/share/repo/src")).toBeTrue()
-  expect(pickerMode("file", "//Server/Share/Repo").selection("//server/share/repo/src", "file.ts")).toBe(
-    "src/file.ts",
-  )
+  expect(pickerMode("file", "//Server/Share/Repo").selection("//server/share/repo/src", "file.ts")).toBe("src/file.ts")
   expect(treePathWithin("/repo", "/repo/../tmp")).toBeFalse()
   expect(treePathWithin("/", "/src")).toBeTrue()
   expect(pickerMode("file", "C:/Repo").selection("c:/repo/src", "file.ts")).toBe("src/file.ts")

+ 5 - 5
packages/app/src/components/directory-picker-domain.ts

@@ -64,7 +64,10 @@ export function pickerMode(mode: "directory" | "file", base?: string) {
 }
 
 export function pickerFileSearchQuery(root: string, input: string, home: string) {
-  const value = input.replace(/\\/g, "/").replace(/^~(?=\/|$)/, home).replace(/\/+$/, "")
+  const value = input
+    .replace(/\\/g, "/")
+    .replace(/^~(?=\/|$)/, home)
+    .replace(/\/+$/, "")
   const base = root.replace(/\\/g, "/").replace(/\/+$/, "")
   if (value === base) return ""
   if (value.startsWith(base + "/")) return value.slice(base.length + 1)
@@ -110,10 +113,7 @@ export function pickerRelativePath(base: string | undefined, path: string) {
   return targetPath.slice(prefix.length)
 }
 
-export function currentPickerSuggestions<T>(
-  result: { query: string; items: readonly T[] } | undefined,
-  query: string,
-) {
+export function currentPickerSuggestions<T>(result: { query: string; items: readonly T[] } | undefined, query: string) {
   if (result?.query !== query) return []
   return result.items
 }