diff --git a/.opencode/commands/browser-setup.md b/.opencode/commands/browser-setup.md new file mode 100644 index 00000000..36c4a01f --- /dev/null +++ b/.opencode/commands/browser-setup.md @@ -0,0 +1,12 @@ +--- +name: browser-setup +description: Guide user through Chrome browser automation setup +--- + +Help the user set up browser automation. + +1. Ask: "Do you have Chrome installed on this computer?" +2. If they say no or are unsure, guide them to install Chrome +3. If yes, check if browser MCP/plugin is available +4. If not available, guide them to install the OpenCode browser extension +5. Once setup is complete, offer to run a simple first task (e.g., "Let's try opening a webpage") diff --git a/packages/app/pr/browser-entry-button.md b/packages/app/pr/browser-entry-button.md new file mode 100644 index 00000000..4d95f033 --- /dev/null +++ b/packages/app/pr/browser-entry-button.md @@ -0,0 +1,114 @@ +# Browser Entry Button + +**Branch:** `feat/browser-entry-button` +**Priority:** P1 + +--- + +## Goal + +Add a single entry button in the empty chat state that triggers browser automation setup via OpenCode command. + +--- + +## Implementation + +### Location +`packages/app/src/app/pages/session.tsx` L1025-1037 + +### Code references +- Empty state render: `packages/app/src/app/pages/session.tsx:1039-1049` +- Command runner used by slash commands: `packages/app/src/app/pages/session.tsx:645-663` (`runOpenCodeCommand`) +- Command registry wiring: `packages/app/src/app/pages/session.tsx:881-892` +- Programmatic command execution: `packages/app/src/app/command-state.ts:293-313` +- `.opencode/commands` loader: `packages/app/src/app/command-state.ts:334` +- Existing button pattern: `packages/app/src/app/pages/dashboard.tsx:557` (`onClick={() => props.runCommand(command)}`) +- Command write API (desktop): `packages/app/src/app/lib/tauri.ts:223` (`opencodeCommandWrite`) +- Frontmatter parser: `packages/app/src/app/utils/index.ts:271` (`parseTemplateFrontmatter`) + +### Current empty state +```tsx + +
+

Start a conversation

+

Describe what you want to do...

+
+
+``` + +### Add button +```tsx + +
+
+ +
+
+

What do you want to do?

+

+ Pick a starting point or just type below. +

+
+
+ +
+
+
+``` + +**Why `runOpenCodeCommand`** +- It handles `$ARGUMENTS` and opens the command run modal when needed (`session.tsx:645-663`) +- Keeps behavior identical to slash commands + +### Create OpenCode command +File: `.opencode/commands/browser-setup.md` + +**App template source:** `packages/app/src/app/data/commands/browser-setup.md` + +If the command is missing in the active workspace, the button auto-writes it via `opencodeCommandWrite` (desktop only) before running. + +```markdown +--- +name: browser-setup +description: Guide user through Chrome browser automation setup +--- + +Help the user set up browser automation. + +1. Ask: "Do you have Chrome installed on this computer?" +2. If they say no or are unsure, guide them to install Chrome +3. If yes, check if browser MCP/plugin is available +4. If not available, guide them to install the OpenCode browser extension +5. Once setup is complete, offer to run a simple first task (e.g., "Let's try opening a webpage") +``` + +--- + +## Flow (handled by LLM) + +1. User clicks "Automate your browser" +2. Command triggers, LLM asks: "Do you have Chrome installed?" +3. User answers Yes/No +4. LLM guides through extension install if needed +5. LLM offers first browser task + +--- + +## NOT doing + +- Custom guided prompts in the UI +- Multiple entry buttons (start with one) +- Hardcoded installation scripts diff --git a/packages/app/src/app/data/commands/browser-setup.md b/packages/app/src/app/data/commands/browser-setup.md new file mode 100644 index 00000000..36c4a01f --- /dev/null +++ b/packages/app/src/app/data/commands/browser-setup.md @@ -0,0 +1,12 @@ +--- +name: browser-setup +description: Guide user through Chrome browser automation setup +--- + +Help the user set up browser automation. + +1. Ask: "Do you have Chrome installed on this computer?" +2. If they say no or are unsure, guide them to install Chrome +3. If yes, check if browser MCP/plugin is available +4. If not available, guide them to install the OpenCode browser extension +5. Once setup is complete, offer to run a simple first task (e.g., "Let's try opening a webpage") diff --git a/packages/app/src/app/pages/session.tsx b/packages/app/src/app/pages/session.tsx index afe22c9e..a97c10e3 100644 --- a/packages/app/src/app/pages/session.tsx +++ b/packages/app/src/app/pages/session.tsx @@ -35,6 +35,9 @@ import WorkspaceChip from "../components/workspace-chip"; import ProviderAuthModal from "../components/provider-auth-modal"; import StatusBar from "../components/status-bar"; import type { OpenworkServerStatus } from "../lib/openwork-server"; +import browserSetupCommandTemplate from "../data/commands/browser-setup.md?raw"; +import { opencodeCommandWrite } from "../lib/tauri"; +import { isTauriRuntime, parseTemplateFrontmatter } from "../utils"; import MessageList from "../components/session/message-list"; import Composer from "../components/session/composer"; @@ -147,6 +150,57 @@ export default function SessionView(props: SessionViewProps) { const agentLabel = createMemo(() => props.selectedSessionAgent ?? "Default agent"); + const buildBrowserSetupCommand = () => { + const parsed = parseTemplateFrontmatter(browserSetupCommandTemplate); + const name = parsed?.data.name?.trim() || "browser-setup"; + const description = + parsed?.data.description?.trim() || "Guide user through Chrome browser automation setup"; + const template = parsed?.body?.trim() || browserSetupCommandTemplate.trim(); + + return { name, description, template }; + }; + + const ensureBrowserSetupCommand = async (): Promise => { + const existing = props.commands.find((item) => item.name === "browser-setup"); + if (existing) return existing; + + if (props.activeWorkspaceDisplay.workspaceType === "remote") { + setCommandToast("Browser setup command is only available in local workspaces."); + return null; + } + + if (!isTauriRuntime()) { + setCommandToast("Browser setup is available in the desktop app."); + return null; + } + + const root = props.activeWorkspaceDisplay.path?.trim() ?? ""; + if (!root) { + setCommandToast("Pick a workspace folder to install the command."); + return null; + } + + try { + const draft = buildBrowserSetupCommand(); + await opencodeCommandWrite({ + scope: "workspace", + projectDir: root, + command: draft, + }); + + return { + name: draft.name, + description: draft.description, + template: draft.template, + scope: "workspace", + }; + } catch (error) { + const message = error instanceof Error ? error.message : "Failed to install browser setup command"; + setCommandToast(message); + return null; + } + }; + const loadAgentOptions = async (force = false) => { if (agentPickerBusy()) return agentOptions(); if (agentPickerReady() && !force) return agentOptions(); @@ -1042,11 +1096,27 @@ export default function SessionView(props: SessionViewProps) {
-

Start a conversation

+

What do you want to do?

- Describe what you want to do, and OpenWork will take it from there. + Pick a starting point or just type below.

+
+ +