* feat(web): Oo computer browser panel with cowork and local preview Wire the in-app browser panel to the active Oo's live Chromium via the computer screen stream, page-browser navigation, and interactive cowork input with AgentCursor. User browser actions become system meta lines in thread context; localhost preview remains as Lokale Vorschau. Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * fix(i18n): sync Lingui catalogs for Oo browser panel Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> * Fix the Oo browser's lint and E2E failures The shared-browser overlay is a focusable input surface, so it gets the application role and a translated label. The local preview focuses the address field again when no page is open, which the split out of InAppBrowser had dropped. The Oo browser spec opens the panel by its exact name, because the signed-up user's name also contains "Browser", and reads the user action from the RPC body's json envelope. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wy1md9QE1ayJbDCwJ4vAQs --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: cynarAI <cynarAI@users.noreply.github.com> Co-authored-by: Claude <noreply@anthropic.com>
36 lines
1.2 KiB
TypeScript
36 lines
1.2 KiB
TypeScript
/** User-visible browser cowork lines for the Oo's thread context (German product copy is applied in UI). */
|
|
|
|
export type BrowserUserActionKind = "navigate" | "click" | "type" | "scroll" | "page_change";
|
|
|
|
export function maskBrowserUserDetail(detail: string, passwordField = false): string {
|
|
if (passwordField) return "••••••";
|
|
const trimmed = detail.trim();
|
|
if (!trimmed) return trimmed;
|
|
if (/password|passwort|pin|secret|token|api[_-]?key/i.test(trimmed)) return "••••••";
|
|
return trimmed.slice(0, 500);
|
|
}
|
|
|
|
export function browserUserContextLine(
|
|
kind: BrowserUserActionKind,
|
|
detail: string,
|
|
passwordField = false,
|
|
): string {
|
|
const safe = maskBrowserUserDetail(detail, passwordField);
|
|
switch (kind) {
|
|
case "navigate":
|
|
return `User navigated to ${safe}`;
|
|
case "click":
|
|
return `User clicked ${safe}`;
|
|
case "type":
|
|
return passwordField ? "User typed in a password field" : `User typed ${safe}`;
|
|
case "scroll":
|
|
return `User scrolled ${safe}`;
|
|
case "page_change":
|
|
return `User page changed to ${safe}`;
|
|
default: {
|
|
const _exhaustive: never = kind;
|
|
return _exhaustive;
|
|
}
|
|
}
|
|
}
|