revert: restore the reviewer-approved tree (97a192d7b)

ZiyaZhang approved 97a192d7b; the subsequent bot-review rounds (7-24)
landed after that approval and were not requested by a human reviewer.
This commit restores the approved tree verbatim as a forward commit
(pushed history stays intact). git diff 97a192d7b is empty.
This commit is contained in:
creatixchu
2026-07-30 09:22:16 +08:00
parent 53e85101b9
commit b46dcb16cb
24 changed files with 149 additions and 771 deletions
@@ -100,22 +100,6 @@ function mount(overrides: Partial<Parameters<typeof DirectoryBrowser>[0]> = {})
return { view, props, listDirectory, createDirectory, onOpen, onClose }
}
/**
* A listDirectory fake whose explicit HOME listings hang for manual
* settlement — the initial open lists home through the absent-path form,
* so only relists and parent legs are held.
*/
function hangingHomeLister() {
const settlers: { resolve: (value: DirectoryListing) => void; reject: (reason: unknown) => void }[] = []
const listDirectory = vi.fn(async (path?: string) => {
if (path === HOME) {
return new Promise<DirectoryListing>((resolve, reject) => { settlers.push({ resolve, reject }) })
}
return listingFor(path)
})
return { listDirectory, settlers }
}
/** The rendered level columns, left-to-right. */
function columns(): HTMLElement[] {
return screen.getAllByRole('list')
@@ -240,94 +224,6 @@ describe('DirectoryBrowser', () => {
expect(within(columns()[1]!).getByText('harness')).toBeTruthy()
})
it('a landing whose new level dropped the focused row parks on the edit zone', async () => {
mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(rowButton(screen.getByRole('listitem')))
await waitFor(() => { expect(columns()).toHaveLength(2) })
// Keyboard is on the right-pane harness row; the home landing has no
// such key, so the focused node unmounts and focus re-parks.
rowButton(within(columns()[1]!).getByRole('listitem')).focus()
fireEvent.click(screen.getByRole('button', { name: 'browser.home' }))
await waitFor(() => { expect(columns()).toHaveLength(1) })
expect(document.activeElement).toBe(screen.getByRole('button', { name: 'browser.editPath' }))
})
it('closing the create dialog parks focus on the edit zone', async () => {
mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(screen.getByRole('button', { name: 'browser.newFolder' }))
const nameInput = screen.getByLabelText('browser.folderName')
fireEvent.keyDown(nameInput, { key: 'Escape' })
// The nested dialog unmounted with focus inside it: re-park.
expect(screen.queryByLabelText('browser.folderName')).toBeNull()
expect(document.activeElement).toBe(screen.getByRole('button', { name: 'browser.editPath' }))
})
it('a pick during the post-create relist supersedes it: late settlements drop', async () => {
const { listDirectory, settlers } = hangingHomeLister()
mount({ listDirectory })
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(screen.getByRole('button', { name: 'browser.newFolder' }))
fireEvent.change(screen.getByLabelText('browser.folderName'), { target: { value: 'ghost' } })
fireEvent.click(screen.getByRole('button', { name: 'browser.create' }))
// The nested dialog is gone while the relist hangs; the card is
// interactive, and picking a row supersedes the relist.
await waitFor(() => { expect(settlers).toHaveLength(1) })
fireEvent.click(rowButton(screen.getByRole('listitem')))
await waitFor(() => { expect(columns()).toHaveLength(2) })
// The stale relist settles late and must not land or select ghost.
await act(async () => { settlers[0]!.resolve({ ...listingFor(HOME), entries: [] }) })
expect(rowButton(within(columns()[0]!).getByRole('listitem')).getAttribute('aria-current')).toBe('true')
})
it('a rejection of a superseded post-create relist is equally silent', async () => {
const { listDirectory, settlers } = hangingHomeLister()
mount({ listDirectory })
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(screen.getByRole('button', { name: 'browser.newFolder' }))
fireEvent.change(screen.getByLabelText('browser.folderName'), { target: { value: 'ghost' } })
fireEvent.click(screen.getByRole('button', { name: 'browser.create' }))
await waitFor(() => { expect(settlers).toHaveLength(1) })
fireEvent.click(rowButton(screen.getByRole('listitem')))
await waitFor(() => { expect(columns()).toHaveLength(2) })
await act(async () => { settlers[0]!.reject(new Error('late')) })
expect(screen.queryByRole('alert')).toBeNull()
expect(columns()).toHaveLength(2)
})
it('a failed create relist parks focus on the edit zone with the error shown', async () => {
let relists = 0
const listDirectory = vi.fn(async (path?: string) => {
if (path === HOME && ++relists > 0) {
throw new DirectoryBrowseError({ code: 'directory-unreadable', message: 'gone', details: { path } })
}
return listingFor(path)
})
mount({ listDirectory })
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(screen.getByRole('button', { name: 'browser.newFolder' }))
fireEvent.change(screen.getByLabelText('browser.folderName'), { target: { value: 'ghost' } })
fireEvent.click(screen.getByRole('button', { name: 'browser.create' }))
await screen.findByRole('alert')
expect(document.activeElement).toBe(screen.getByRole('button', { name: 'browser.editPath' }))
})
it('Escape over a dot-revealed focused row re-parks on the edit zone as the row re-hides', async () => {
mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(screen.getByRole('button', { name: 'browser.editPath' }))
fireEvent.change(screen.getByLabelText<HTMLInputElement>('browser.editPath'), { target: { value: `${HOME}/.co` } })
const row = rowButton(screen.getByRole('listitem'))
expect(row.textContent).toBe('.config')
row.focus()
fireEvent.keyDown(row, { key: 'Escape' })
// The cleared draft re-hides the revealed row under the focused cursor;
// the body guard sees the fall and parks on the edit zone.
expect(screen.queryByText('.config')).toBeNull()
expect(document.activeElement).toBe(screen.getByRole('button', { name: 'browser.editPath' }))
})
it('a navigation to the filesystem root keeps the single wide level', async () => {
mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
@@ -374,81 +270,6 @@ describe('DirectoryBrowser', () => {
expect(rowButton(screen.getByRole('listitem')).getAttribute('aria-current')).toBeNull()
})
it('re-parks focus on the re-selected row when the upgrade displaces focused rows', async () => {
const { listDirectory, settlers } = hangingHomeLister()
mount({ listDirectory })
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(screen.getByRole('button', { name: 'browser.editPath' }))
fireEvent.change(screen.getByLabelText<HTMLInputElement>('browser.editPath'), { target: { value: DOCS } })
fireEvent.keyDown(screen.getByLabelText('browser.editPath'), { key: 'Enter' })
// The committed landing is interactive; Tab reaches its rows while the
// parent leg is still in flight.
await waitFor(() => { expect(screen.getByRole('listitem').textContent).toBe('harness') })
rowButton(screen.getByRole('listitem')).focus()
await waitFor(() => { expect(settlers).toHaveLength(1) })
// The upgrade replaces every committed row node; focus re-parks on the
// re-selected row instead of falling to body.
await act(async () => { settlers[0]!.resolve(listingFor(HOME)) })
await waitFor(() => { expect(columns()).toHaveLength(2) })
expect(document.activeElement?.textContent).toBe('Documents')
expect(document.activeElement?.getAttribute('aria-current')).toBe('true')
})
it('a UNC level is home-collapsed and filters decorated UNC drafts without popping the share root', async () => {
const SHARE = '\\\\server\\share'
const listing: DirectoryListing = {
path: `${SHARE}\\x`,
home: `${SHARE}\\x`,
crumbs: [
{ name: `${SHARE}\\`, path: `${SHARE}\\`, hidden: false },
{ name: 'x', path: `${SHARE}\\x`, hidden: false },
],
entries: [{ name: 'Alpha', path: `${SHARE}\\x\\Alpha`, hidden: false }],
truncated: false,
}
const listDirectory = vi.fn(async () => listing)
mount({ listDirectory })
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
expect(columns()).toHaveLength(1)
expect(screen.getByRole('button', { name: 'browser.home' })).toBeTruthy()
// A decorated UNC draft (doubled separator, share-root-crossing dot-dot)
// still normalizes to the listed level: the filter matches what Enter
// would navigate to, and \\server\share stays unpoppable.
fireEvent.click(screen.getByRole('button', { name: 'browser.editPath' }))
const input = screen.getByLabelText<HTMLInputElement>('browser.editPath')
fireEvent.change(input, { target: { value: '\\\\server\\\\share\\..\\x\\a' } })
expect(screen.getByText('Alpha')).toBeTruthy()
fireEvent.change(input, { target: { value: `${SHARE}\\x\\z` } })
expect(screen.queryByRole('listitem')).toBeNull()
})
it('collapses a typed-case Windows home to the display root (single pane, Home crumb)', async () => {
const CANON = 'C:\\Users\\Alice'
const TYPED = 'c:\\users\\alice'
const typedHome: DirectoryListing = {
path: TYPED,
home: CANON,
crumbs: [
{ name: 'C:\\', path: 'C:\\', hidden: false },
{ name: 'users', path: 'c:\\users', hidden: false },
{ name: 'alice', path: TYPED, hidden: false },
],
entries: [{ name: 'Desktop', path: `${CANON}\\Desktop`, hidden: false }],
truncated: false,
}
const canonHome: DirectoryListing = { ...typedHome, path: CANON, crumbs: typedHome.crumbs }
mount({ listDirectory: vi.fn(async (path?: string) => (path === TYPED ? typedHome : canonHome)) })
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(screen.getByRole('button', { name: 'browser.editPath' }))
fireEvent.change(screen.getByLabelText<HTMLInputElement>('browser.editPath'), { target: { value: TYPED } })
fireEvent.keyDown(screen.getByLabelText('browser.editPath'), { key: 'Enter' })
// Case-folded home comparison: the typed-case home is still the display
// root — single pane, collapsed Home crumb, no parent leg.
await waitFor(() => { expect(screen.getByRole('listitem').textContent).toBe('Desktop') })
expect(columns()).toHaveLength(1)
expect(screen.getByRole('button', { name: 'browser.home' })).toBeTruthy()
})
it('keeps the single-pane landing when the truncated parent level lacks the target', async () => {
const listDirectory = vi.fn(async (path?: string) => {
// The parent leg names HOME explicitly; serve it a truncated window
@@ -482,7 +303,7 @@ describe('DirectoryBrowser', () => {
path: TYPED,
home: ROOT,
crumbs: [{ name: 'C:\\', path: ROOT, hidden: false }, { name: 'users', path: TYPED, hidden: false }],
entries: [{ name: 'Alpha', path: `${TYPED}\\Alpha`, hidden: false }],
entries: [],
truncated: false,
}
mount({ listDirectory: vi.fn(async (path?: string) => (path === TYPED ? winUsers : winRoot)) })
@@ -496,23 +317,6 @@ describe('DirectoryBrowser', () => {
expect(rowButton(within(columns()[0]!).getByRole('listitem')).getAttribute('aria-current')).toBe('true')
})
expect(within(columns()[0]!).getByText('Users')).toBeTruthy()
// The editor seeds from the actual-cased selection while the child
// level still carries the typed case: the draft's directory part folds
// per platform, so the right pane keeps prefix-filtering.
fireEvent.click(screen.getByRole('button', { name: 'browser.editPath' }))
const input = screen.getByLabelText<HTMLInputElement>('browser.editPath')
expect(input.value).toBe('C:\\Users\\')
fireEvent.change(input, { target: { value: 'C:\\Users\\a' } })
expect(within(columns()[1]!).getByText('Alpha')).toBeTruthy()
fireEvent.change(input, { target: { value: 'C:\\Users\\z' } })
expect(within(columns()[1]!).queryAllByRole('listitem')).toHaveLength(0)
// Forward-slash drafts are equally legal on win32 (Enter navigates
// them); the filter folds them instead of going silent.
fireEvent.change(input, { target: { value: 'C:/Users/a' } })
expect(within(columns()[1]!).getByText('Alpha')).toBeTruthy()
// Dot segments normalize on win32 too.
fireEvent.change(input, { target: { value: 'C:\\Users\\.\\a' } })
expect(within(columns()[1]!).getByText('Alpha')).toBeTruthy()
})
it('re-parks focus on the edit zone when a failed pick unmounts a dot-revealed row', async () => {
@@ -645,14 +449,6 @@ describe('DirectoryBrowser', () => {
// A draft naming some other directory (or none) leaves the level whole.
fireEvent.change(input, { target: { value: 'no-separator' } })
expect(screen.getByRole('listitem').textContent).toBe('Documents')
// Dot segments and repeated separators are legal for Enter, so the
// filter's directory comparison normalizes them the same way.
fireEvent.change(input, { target: { value: `${HOME}/./do` } })
expect(screen.getByRole('listitem').textContent).toBe('Documents')
fireEvent.change(input, { target: { value: `${HOME}//do` } })
expect(screen.getByRole('listitem').textContent).toBe('Documents')
fireEvent.change(input, { target: { value: `${HOME}/foo/../do` } })
expect(screen.getByRole('listitem').textContent).toBe('Documents')
})
it('filters the child pane in two-pane mode and follows the draft back up a level', async () => {
@@ -770,55 +566,6 @@ describe('DirectoryBrowser', () => {
expect(screen.getByRole('button', { name: 'browser.home' })).toBeTruthy()
})
it('a plain right-pane advance parks focus on the new selection (no editor involved)', async () => {
mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
fireEvent.click(rowButton(screen.getByRole('listitem')))
await waitFor(() => { expect(columns()).toHaveLength(2) })
// Keyboard reached the right pane; the advance replaces that whole
// column, so focus re-parks on the new left pane's selected row.
const row = rowButton(within(columns()[1]!).getByRole('listitem'))
row.focus()
fireEvent.click(row)
await waitFor(() => { expect(document.activeElement?.textContent).toBe('harness') })
expect(document.activeElement?.getAttribute('aria-current')).toBe('true')
})
it('a create landing parks focus on the created row', async () => {
const b = mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
b.listDirectory.mockImplementation(async (path?: string) => {
// The created directory is not in listingFor's fixed tree: serve its
// level before the fixture lookup can reject the unknown path.
if (path === `${HOME}/fresh`) return { ...listingFor(HOME), path: `${HOME}/fresh`, entries: [] }
const base = listingFor(path)
if (path === HOME) {
return { ...base, entries: [...base.entries, { name: 'fresh', path: `${HOME}/fresh`, hidden: false }] }
}
return base
})
fireEvent.click(screen.getByRole('button', { name: 'browser.newFolder' }))
fireEvent.change(screen.getByLabelText('browser.folderName'), { target: { value: 'fresh' } })
fireEvent.click(screen.getByRole('button', { name: 'browser.create' }))
await waitFor(() => { expect(document.activeElement?.textContent).toBe('fresh') })
expect(document.activeElement?.getAttribute('aria-current')).toBe('true')
})
it('a create landing whose truncated relist lost the created row parks on the edit zone', async () => {
const b = mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
// The relist window misses the created directory (truncated tail).
b.listDirectory.mockImplementation(async (path?: string) => ({ ...listingFor(path), truncated: true }))
fireEvent.click(screen.getByRole('button', { name: 'browser.newFolder' }))
fireEvent.change(screen.getByLabelText('browser.folderName'), { target: { value: 'zzz-tail' } })
fireEvent.click(screen.getByRole('button', { name: 'browser.create' }))
// No aria-current row exists for the selection: focus falls back to the
// crumb edit zone instead of staying wherever it fell.
await waitFor(() => {
expect(document.activeElement).toBe(screen.getByRole('button', { name: 'browser.editPath' }))
})
})
it('a right-pane pick while editing parks focus on the advanced selection', async () => {
mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
@@ -1198,7 +945,6 @@ describe('DirectoryBrowser', () => {
expect(cancels.map(button => button.disabled).sort()).toEqual([false, true])
expect(screen.getByRole<HTMLButtonElement>('button', { name: 'browser.open' }).disabled).toBe(true)
expect(screen.getByRole<HTMLButtonElement>('button', { name: 'browser.editPath' }).disabled).toBe(true)
expect(screen.getByRole<HTMLButtonElement>('button', { name: 'browser.showHidden' }).disabled).toBe(true)
for (const row of screen.getAllByRole('listitem')) {
expect(rowButton(row).disabled).toBe(true)
}
@@ -1408,59 +1154,6 @@ describe('DirectoryBrowser', () => {
expect(screen.getByText('browser.createIn:/srv/data')).toBeTruthy()
})
it('a crumb-less Windows level still seeds the editor with a backslash', async () => {
// The empty chain degrades separatorOf to the home-text read; the
// backslash side of that fallback is the Windows shape.
const bare: DirectoryListing = { path: 'C:\\srv', home: 'C:\\Users\\u', crumbs: [], entries: [], truncated: false }
mount({ listDirectory: vi.fn(async () => bare) })
await waitFor(() => {
expect(screen.getByRole<HTMLButtonElement>('button', { name: 'browser.editPath' }).disabled).toBe(false)
})
fireEvent.click(screen.getByRole('button', { name: 'browser.editPath' }))
expect(screen.getByLabelText<HTMLInputElement>('browser.editPath').value).toBe('C:\\srv\\')
})
it('a POSIX home whose name contains a backslash still reads as the display root', async () => {
const WEIRD = '/home/we\\ird'
const listing: DirectoryListing = {
path: WEIRD,
home: WEIRD,
crumbs: [
{ name: '/', path: '/', hidden: false },
{ name: 'home', path: '/home', hidden: false },
{ name: 'we\\ird', path: WEIRD, hidden: false },
],
entries: [{ name: 'notes', path: `${WEIRD}/notes`, hidden: false }],
truncated: false,
}
const listDirectory = vi.fn(async () => listing)
mount({ listDirectory })
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
// The root crumb ('/') decides the platform: the backslash in the name
// neither flips the fold nor breaks the Home collapse.
expect(columns()).toHaveLength(1)
expect(screen.getByRole('button', { name: 'browser.home' })).toBeTruthy()
expect(listDirectory).toHaveBeenCalledTimes(1)
})
it('pointer-toggling hidden off keeps focus on the toggle as the focused row re-hides', async () => {
mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
const toggle = screen.getByRole('button', { name: 'browser.showHidden' })
fireEvent.click(toggle)
fireEvent.click(screen.getByRole('button', { name: 'browser.editPath' }))
// Tab parked focus on the revealed hidden row; the pointer click below
// would unmount it (toggle off + empty seeded prefix hides it again).
const hiddenRow = within(columns()[0]!).getByText('.config').closest('button')!
hiddenRow.focus()
fireEvent.mouseDown(toggle)
fireEvent.click(toggle)
expect(screen.queryByText('.config')).toBeNull()
expect(document.activeElement).toBe(toggle)
// The editor survives the whole exchange.
expect(screen.getByLabelText('browser.editPath', { selector: 'input' })).toBeTruthy()
})
it('refuses to close the nested dialog while the creation is in flight', async () => {
const b = mount()
await waitFor(() => { expect(screen.getByRole('listitem')).toBeTruthy() })
@@ -1,43 +0,0 @@
/**
* The wire contract's home shape: a decorated HOME (trailing/repeated
* separators, dot segments — homedir() ships it verbatim) still leaves the
* listing carrying the resolved form, matching `path` and `crumbs[].path`.
* The mock points homedir at a scratch tree so the probe never scans the
* running machine's real home (same hermetic reasoning as service.spec's
* temporary tree); the mock spreads the actual module, so tmpdir stays real.
*/
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join, resolve } from 'node:path'
import { afterAll, beforeAll, expect, it, vi } from 'vitest'
import { Context } from 'cordis'
let scratch: string
vi.mock('node:os', async (importOriginal) => {
const actual = await importOriginal<typeof import('node:os')>()
return { ...actual, homedir: () => `${scratch}/.//.` }
})
beforeAll(async () => {
scratch = await mkdtemp(join(tmpdir(), 'dsh-home-shape-'))
})
afterAll(async () => {
await rm(scratch, { recursive: true, force: true })
})
it('resolves a decorated homedir before stamping listing.home', async () => {
const { default: BrowseDirectoryPicker } = await import('../src/index.ts')
const ctx = new Context()
const fiber = ctx.plugin(BrowseDirectoryPicker)
await fiber.await()
const picked = ctx.get('directoryPicker')!.capability()
if (picked.kind !== 'browse') throw new Error('browse backend must advertise the browse capability')
const listing = await picked.list()
expect(listing.home).toBe(resolve(scratch))
expect(listing.path).toBe(listing.home)
expect(listing.crumbs.at(-1)!.path).toBe(listing.home)
await fiber.dispose()
})
@@ -2,7 +2,7 @@
import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises'
import { homedir, tmpdir } from 'node:os'
import { basename, join, resolve } from 'node:path'
import { basename, join } from 'node:path'
import { afterAll, beforeAll, describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { DirectoryPickerError } from '@deepseek-ai/dsh-host-directory-picker'
@@ -48,9 +48,7 @@ describe('BrowseDirectoryPicker', () => {
it('lists directories only, flags hidden rows, follows symlinks, skips broken links, sorts by name', async () => {
const listing = await capability.list(root)
expect(listing.path).toBe(root)
// The environment may decorate HOME; every listing path ships in the
// DirectoryListing contract's canonical shape, home included.
expect(listing.home).toBe(resolve(homedir()))
expect(listing.home).toBe(homedir())
expect(listing.entries.map(entry => entry.name)).toEqual(['.hidden-dir', 'linked', 'projects'])
expect(listing.entries.map(entry => entry.hidden)).toEqual([true, false, false])
// Every entry path is absolute and host-joined — clients never join segments.
@@ -163,6 +161,11 @@ describe('BrowseDirectoryPicker', () => {
expect(listing.crumbs[0]!.name).toBe(listing.crumbs[0]!.path)
})
it('lists the home directory when no path is given', async () => {
const listing = await capability.list()
expect(listing.path).toBe(homedir())
})
it('throws directory-unreadable for a missing target', async () => {
const missing = join(root, 'no-such-dir')
const failure = await capability.list(missing).catch((error: unknown) => error)
@@ -203,18 +206,10 @@ describe('BrowseDirectoryPicker', () => {
})
it('creates one child directory and surfaces it in the next listing', async () => {
// The composed-form name (U+00E9) doubles as the name-rewriting
// tripwire: a volume that stores names NFD-decomposed hands back a
// different dirent.name and the equality below goes red — the README's
// documented boundary.
const created = await capability.createDirectory(root, 'café')
expect(created).toBe(join(root, 'café'))
const created = await capability.createDirectory(root, 'fresh')
expect(created).toBe(join(root, 'fresh'))
const listing = await capability.list(root)
expect(listing.entries.map(entry => entry.name)).toContain('café')
// The contract's cross-method equality: the returned path is verbatim
// the child's entries[].path (clients anchor the create landing's
// selection and focus on it).
expect(listing.entries.find(entry => entry.name === 'café')!.path).toBe(created)
expect(listing.entries.map(entry => entry.name)).toContain('fresh')
})
it('refuses an existing child with directory-exists', async () => {