mirror of
https://github.com/stablyai/orca.git
synced 2026-10-08 08:02:32 +00:00
* fix(browser-preview): require explicit preview capabilities (STA-5758) Scope document reads to approved directories, confirm external links before opening them, revoke grants with tab lifecycle, and keep document-preview session state rollback-safe across mixed client/runtime versions. * Harden document preview lifecycle and permissions * Document preview DNS prefetch residual * Make preview E2E guest focus explicit * fix(browser-preview): entry-file-only authority for root-level docs, contained chip layout, re-issued gate paths (STA-5758) A grant whose document directory is its own request base — a doc at the workspace root, or outside any workspace — now reads nothing but the entry file until the reader approves a directory, at both the lexical and the canonical containment pass. The DNS-prefetch residual can only beacon what the page can read, and a root-level document could previously read the whole worktree silently. The identity chip's host badge overflowed the chip's layout box under squeeze (Linux CI): every row member can now shrink and truncate, verified by a width sweep in isolated Chromium down to ~120px chips. The Allow banner says what it grants: 'Allow folder', reading files in the named directory, for the life of the preview. The reliability-gate manifest command, testFiles entry, assertion refs and dated evidence naming the deleted doc-preview-external-link-bridge.test.ts are re-issued at doc-preview-external-link-confirmation.test.ts with a fresh 189/189 run; the focus-gate assertion text follows the shipped gate. * fix(browser-preview): hide the chip identity row below 24rem instead of clipping it, ellipsize the host badge, catalog the new i18n keys (STA-5758) CI's preview pane leaves the chip ~40px: no truncation shows anything there, so the Workspace-file label and host badge now hide whole below a 24rem container threshold sized so that visible implies contained. The badge text gains an inner text box — text directly inside the flex pill clipped both ends with no ellipsis. The e2e geometry oracle asserts containment when the row shows and the threshold when it does not. verify:localization-catalog: the hardening's new preview keys (and the renamed allowDirectory) join en.json via sync:localization-catalog. * feat(browser-preview): batch blocked folders into one access decision (STA-5758) Sequential per-folder banners trained the allow reflex without adding judgment — a reader cannot weigh assets/ against data/. The banner now accumulates every folder a load surfaces, names them (three, then a count, full list in the title), and grants exactly that set with one Allow-N-folders click and one reload. Dismiss fences the whole named set. The map lives behind a ref with a version tick so a dismissal fences an offer landing in the same event batch.
52 lines
1.6 KiB
TypeScript
52 lines
1.6 KiB
TypeScript
import type {
|
|
BrowserPage,
|
|
BrowserPageDocLocation,
|
|
BrowserWorkspace
|
|
} from './browser-workspace-types'
|
|
import { relativePathInsideRoot, resolveRuntimePath } from './cross-platform-path'
|
|
|
|
/**
|
|
* Why an explicit comparison and not object identity: the mirror rebuilds the workspace's copy of
|
|
* this on every page change, so identity is never equal and the store would write a new workspace
|
|
* object — and republish the tab — on every unrelated update.
|
|
*/
|
|
export function browserPageDocLocationsEqual(
|
|
left: BrowserPageDocLocation | null,
|
|
right: BrowserPageDocLocation | null
|
|
): boolean {
|
|
if (left === null || right === null) {
|
|
return left === right
|
|
}
|
|
return left.worktreeId === right.worktreeId && left.filePath === right.filePath
|
|
}
|
|
|
|
/** True for a page or tab that shows a workspace document rather than a URL. */
|
|
export function isWorkspaceDocSurface(
|
|
surface: Pick<BrowserPage | BrowserWorkspace, 'docLocation'>
|
|
): boolean {
|
|
return Boolean(surface.docLocation)
|
|
}
|
|
|
|
export function remapBrowserPageDocLocation(
|
|
location: BrowserPageDocLocation,
|
|
oldWorktreeId: string,
|
|
newWorktreeId: string,
|
|
oldWorktreePath?: string,
|
|
newWorktreePath?: string
|
|
): BrowserPageDocLocation {
|
|
if (location.worktreeId !== oldWorktreeId) {
|
|
return location
|
|
}
|
|
const relativePath =
|
|
oldWorktreePath && newWorktreePath
|
|
? relativePathInsideRoot(oldWorktreePath, location.filePath)
|
|
: null
|
|
return {
|
|
...location,
|
|
worktreeId: newWorktreeId,
|
|
...(relativePath !== null && newWorktreePath
|
|
? { filePath: resolveRuntimePath(newWorktreePath, relativePath) }
|
|
: {})
|
|
}
|
|
}
|