Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The runner saves screenshots, ARIA, console, Client diagnostics, canonical reque

### Phone: choose the folder from the Host

`node scripts/e2e-mobile-folder-browse-web.mjs` drives the same request card in the Expo Web export of the phone app (behavior `desktop.grants.request-write-continue`). A real model asks for a folder, the phone proxy answers DSH `directoryPicker/list` with `directory-picker/unavailable` as a Windows/macOS system-chooser Host does, and the sheet must still list Host folders through `botharness/folderBrowse`: subfolders only, no files, no hidden folders, plus Home and `/` (drives on Windows) under **Other places**. Choosing **Authorize this folder** then **Allow read/write** must leave a writable Grant on exactly that path. The CLI twin is `deepseekbot folder-browse [<path>]`. This is layout and flow evidence, not native-device evidence.
`node scripts/e2e-mobile-folder-browse-web.mjs` drives the same request card in the Expo Web export of the phone app (behavior `desktop.grants.request-write-continue`). A real model asks for a folder, the phone proxy answers DSH `directoryPicker/list` with `directory-picker/unavailable` as a Windows/macOS system-chooser Host does, and the sheet must still list Host folders through `botharness/folderBrowse`: subfolders only, no files, no hidden folders, plus Home and `/` (drives on Windows) under **Other places**. The sheet names the folder it will grant (**Will authorize: <path>**); choosing **Authorize this folder** then **Allow read/write** must leave a writable Grant on exactly that path. The CLI twin is `deepseekbot folder-browse [<path>]`. This is layout and flow evidence, not native-device evidence.

## Gotchas

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion apps/mobile/src/ui/chat/folder-picker-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
SheetNote,
SHEET_GROUP,
} from './sheet';
import { Crumbs, Grouped, locationSection, RowIcon } from './workspace-sheet';
import { Crumbs, Grouped, locationSection, OpenFolderTarget, RowIcon } from './workspace-sheet';

export interface FolderPickerPort {
listFolders(path?: string): Promise<HostFolderListing>;
Expand Down Expand Up @@ -255,6 +255,7 @@ export function FolderPickerSheet({
</Grouped>
)}
/>
{manual ? null : <OpenFolderTarget listing={listing} />}
<SheetActions>
<Button label={t.cancel} on="canvas" disabled={busy !== undefined} onPress={close} />
<Button
Expand Down
7 changes: 7 additions & 0 deletions apps/mobile/src/ui/chat/workspace-sheet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ type BrowseRow =

const OFF = 'off';

export function OpenFolderTarget({ listing }: { listing: Loadable<HostFolderListing> }) {
return listing.status === 'ready' ? (
<SheetNote>{t.authorizeTarget(listing.value.path)}</SheetNote>
) : null;
}

export function locationSection(listing: HostFolderListing) {
const data = listing.roots
.map((root, index) => ({
Expand Down Expand Up @@ -529,6 +535,7 @@ export function WorkspaceSheet({
</Grouped>
)}
/>
<OpenFolderTarget listing={listing} />
<SheetActions>
<Button
label={t.back}
Expand Down
2 changes: 2 additions & 0 deletions apps/mobile/src/ui/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1041,6 +1041,7 @@ const en = {
folderPathHint: '/Users/you/Project',
registeredFolders: 'Folders registered on your computer',
authorizeHere: 'Authorize this folder',
authorizeTarget: (path: string) => `Will authorize: ${path}`,
authorize: 'Authorize',
confirmGrant: (name: string) => `Confirm authorization for ${name}`,
grantScope: 'Only shares this folder with this Bot. Other permissions stay the same.',
Expand Down Expand Up @@ -2124,6 +2125,7 @@ const zh: typeof en = {
folderPathHint: '/Users/you/Project',
registeredFolders: '已在电脑上登记的文件夹',
authorizeHere: '授权此文件夹',
authorizeTarget: (path: string) => `将授权:${path}`,
authorize: '授权',
confirmGrant: (name: string) => `确认授权给 ${name}`,
grantScope: '只把这个文件夹授权给此 Bot,其他权限不变。',
Expand Down
15 changes: 15 additions & 0 deletions apps/mobile/test/grant-request-card.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,21 @@ describe('Folder request card', () => {
expect(view.querySelector('[role="dialog"]')).toBeNull();
});

it('names the open folder it will authorize after backing out of a registered pick', async () => {
const fake = host();
const view = await render(card(connect(fake)));
await press(button(view, t.grantChoose));
const registered = [...view.querySelectorAll<HTMLButtonElement>('button[aria-label]')].find(
(node) => node.getAttribute('aria-label')!.includes(PROJECT.path),
)!;
await press(registered);
expect(view.textContent).toContain(t.grantConfirm('Ada'));
await press(button(view, t.back));
expect(view.textContent).toContain(t.authorizeTarget('/Users/qa'));
expect(view.textContent).not.toContain(t.authorizeTarget(PROJECT.path));
expect(approvals(fake)).toEqual([]);
});

it('sends nothing when the picker is cancelled', async () => {
const fake = host();
const view = await render(card(connect(fake)));
Expand Down
11 changes: 11 additions & 0 deletions changes/2421-phone-folder-target.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
section: Fixed
---

## en

- The phone folder picker's authorize button now names the folder it will grant, so backing out of a registered folder no longer leaves an unlabeled button that grants the folder you were browsing ([#2421](https://github.com/BotHarness/DeepSeekBot/pull/2421)).

## zh

- 手机文件夹选择器的授权按钮现在会写明要授权的文件夹。从已登记文件夹的确认页返回后,不会再出现一个看不出授权对象、实际授权当前所在文件夹的按钮([#2421](https://github.com/BotHarness/DeepSeekBot/pull/2421))。
4 changes: 4 additions & 0 deletions scripts/e2e-mobile-folder-browse-web.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,10 @@ async function main() {
await shot('2-browse-folder');
steps.push('opened a folder: subfolders only, no files and no hidden folders');

checks.namesTarget = await page.evaluate(
(path) => document.body.innerText.includes(`Will authorize: ${path}`),
fixture,
);
await page.locator('::-p-aria(Authorize this folder)').click();
await text('Allow read/write');
await shot('3-confirm');
Expand Down
2 changes: 1 addition & 1 deletion scripts/verification-inventory.json
Original file line number Diff line number Diff line change
Expand Up @@ -1609,7 +1609,7 @@
"behaviors": ["desktop.grants.request-write-continue"],
"reason": "Own task Host and Expo Web export; real model folder request, system-chooser refusal simulated at the phone proxy, phone browses Host folders and grants one; not native-device evidence.",
"task": 2080,
"sha256": "74fac4cc7686abd76dceb9fc50e950691eb5d3321261f57132a562be3e2b648d"
"sha256": "3493bdbcf12a110cd430f61d598a632d930989d020d48a12f0a2e4a8e93c1c62"
},
{
"path": "scripts/e2e-mobile-working-web.mjs",
Expand Down
Loading