diff --git a/QUICKSTART.md b/QUICKSTART.md index 23f20c119..52012064c 100644 --- a/QUICKSTART.md +++ b/QUICKSTART.md @@ -13,7 +13,7 @@ Run the full product locally. ### Local agent CLI and PATH -The daemon scans your **`PATH`** (plus common user toolchain directories). If you install a CLI with **`npm install -g`** or **Homebrew** and Open Design still shows it as *not installed*, the GUI may be starting with a minimal `PATH` that does not include your global npm or Homebrew `bin` directory (common on macOS when the app is not launched from a full login shell). Ensure the executable’s directory is on `PATH` for the process that runs the daemon, then use **Rescan** in **Settings → Execution & model**. +The daemon scans your **`PATH`** (plus common user toolchain directories). If you install a CLI with **`npm install -g`** or **Homebrew** and Open Design still shows it as *not installed*, the GUI may be starting with a minimal `PATH` that does not include your global npm or Homebrew `bin` directory (common on macOS when the app is not launched from a full login shell). Ensure the executable’s directory is on `PATH` for the process that runs the daemon, then use **Rescan** in **Settings → Execution mode**. `nvm` / `fnm` are optional convenience tools, not required project setup. If you use one, install/select Node 24 before running pnpm: @@ -349,7 +349,7 @@ open-design/ claude auth status --text printf 'hello' | claude -p --output-format stream-json --verbose --permission-mode bypassPermissions ``` - If the smoke test reports `401`, `apiKeySource: "none"`, or another auth error without a custom endpoint, run `claude`, use `/login`, exit Claude, and retry Open Design. If you use multiple Claude profiles, set **Settings -> Execution & model -> Claude Code config directory** to the profile path such as `~/.claude-2`. If `ANTHROPIC_BASE_URL` or a proxy is set, check the endpoint URL, proxy credentials, endpoint auth environment, and model access; remove the custom endpoint only if you want to retry with standard Claude Code auth. On Windows, native PowerShell and WSL use separate Claude installs and credential stores; re-authenticate in the same environment Open Design uses, and check Windows Credential Manager if `/login` does not repair native Windows credentials. + If the smoke test reports `401`, `apiKeySource: "none"`, or another auth error without a custom endpoint, run `claude`, use `/login`, exit Claude, and retry Open Design. If you use multiple Claude profiles, set **Settings -> Execution mode -> Claude Code config directory** to the profile path such as `~/.claude-2`. If `ANTHROPIC_BASE_URL` or a proxy is set, check the endpoint URL, proxy credentials, endpoint auth environment, and model access; remove the custom endpoint only if you want to retry with standard Claude Code auth. On Windows, native PowerShell and WSL use separate Claude installs and credential stores; re-authenticate in the same environment Open Design uses, and check Windows Credential Manager if `/login` does not repair native Windows credentials. - **daemon 500 on /api/chat** — check the daemon terminal for the stderr tail; usually the CLI rejected its args. Different CLIs take different argv shapes; see `apps/daemon/src/agents.ts` `buildArgs` if you need to tweak. - **media generation says `OD_BIN` is missing or daemon URL is `:0`** — run the media dispatcher checks above. Do not resume the old CLI session; reopen the project from the Open Design app so the daemon can inject fresh `OD_*` variables. - **Codex loads too much plugin context** — start Open Design with `OD_CODEX_DISABLE_PLUGINS=1 pnpm tools-dev` to make daemon-spawned Codex processes run with `--disable plugins`. diff --git a/apps/web/src/components/ConnectorsBrowser.tsx b/apps/web/src/components/ConnectorsBrowser.tsx index 738e4f198..6f24f25c1 100644 --- a/apps/web/src/components/ConnectorsBrowser.tsx +++ b/apps/web/src/components/ConnectorsBrowser.tsx @@ -25,6 +25,7 @@ import { } from './EntryView'; import { Icon } from './Icon'; import { CenteredLoader } from './Loading'; +import { Toast } from './Toast'; const CONNECTOR_CALLBACK_MESSAGE_TYPE = 'open-design:connector-connected'; const CONNECTOR_AUTH_PENDING_STORAGE_KEY = 'od-connectors-authorization-pending'; @@ -556,6 +557,7 @@ export function ConnectorsBrowser({ const [connectorAuthorizationPending, setConnectorAuthorizationPending] = useState(() => loadConnectorAuthorizationPending()); const [connectorAuthorizationCancelFailed, setConnectorAuthorizationCancelFailed] = useState>({}); const [connectorAuthorizationError, setConnectorAuthorizationError] = useState>({}); + const [connectErrorToast, setConnectErrorToast] = useState(null); const [detailConnectorId, setDetailConnectorId] = useState(null); const [toolPreviewLoadingIds, setToolPreviewLoadingIds] = useState>({}); const [toolPreviewFetchedIds, setToolPreviewFetchedIds] = useState>({}); @@ -710,6 +712,7 @@ export function ConnectorsBrowser({ const result = await connectConnector(connectorId); updateConnector(result.connector); if (result.connector && !result.error) { + setConnectErrorToast(null); setConnectorAuthorizationPending((curr) => updateConnectorAuthorizationPendingFromConnectResponse(curr, { connector: result.connector!, ...(result.auth === undefined ? {} : { auth: result.auth }), @@ -717,7 +720,7 @@ export function ConnectorsBrowser({ } else { setConnectorAuthorizationPending((curr) => clearConnectorAuthorizationPending(curr, connectorId)); if (result.error) { - setConnectorAuthorizationError((curr) => ({ ...curr, [connectorId]: result.error! })); + setConnectErrorToast(result.error); } } } else { @@ -815,6 +818,15 @@ export function ConnectorsBrowser({ return (
+ {connectErrorToast ? ( +
+ setConnectErrorToast(null)} + /> +
+ ) : null}
@@ -1173,11 +1185,6 @@ function ConnectorCard({ ) : null}
- {authorizationError ? ( -

- {authorizationError} -

- ) : null} {authorizationCancelFailed ? (

{AUTHORIZATION_CANCEL_FAILED_MESSAGE} @@ -1343,11 +1350,6 @@ function ConnectorDetailDrawer({ ) : null} ) : null} - {authorizationError ? ( -

- {authorizationError} -

- ) : null} {authorizationCancelFailed ? (

{AUTHORIZATION_CANCEL_FAILED_MESSAGE} diff --git a/apps/web/src/components/DesignSystemsSection.tsx b/apps/web/src/components/DesignSystemsSection.tsx index 7f47b923d..c7626723e 100644 --- a/apps/web/src/components/DesignSystemsSection.tsx +++ b/apps/web/src/components/DesignSystemsSection.tsx @@ -107,13 +107,6 @@ export function DesignSystemsSection({ cfg, setCfg }: Props) { return (

-
-
-

{t('settings.designSystems')}

-

{t('settings.designSystemsHint')}

-
-
-
); + case 'info': + return ( + + + + + + ); case 'kanban': return ( @@ -435,6 +446,19 @@ export function Icon({ name, size = 14, strokeWidth = 1.6, ...rest }: Props) { ); + case 'sun': + return ( + + + + + ); + case 'moon': + return ( + + + + ); case 'sun-moon': return ( diff --git a/apps/web/src/components/McpClientSection.tsx b/apps/web/src/components/McpClientSection.tsx index 244289e3d..d3abed5fd 100644 --- a/apps/web/src/components/McpClientSection.tsx +++ b/apps/web/src/components/McpClientSection.tsx @@ -366,10 +366,7 @@ export const McpClientSection = forwardRef(

External MCP servers

-

- Surface tools from third-party MCP servers (Higgsfield, GitHub, - filesystem…) to your coding agent. -

+

Third-party tools for your coding agent.

+ {flash?.kind === 'pathCopied' ? ( + + {flashLabel.pathCopied} + + ) : null} + + ) : null} +

{t('settings.memoryDescription')}

) : ( -
+ /* + BYOK panel — wrap the per-protocol form in a bordered card so + the chips above (Anthropic / OpenAI / Azure / Gemini / Ollama) + visually own the content below. Without the card, the chip + row and the form looked like two unrelated stripes; users + had no anchor for "this is what I configured for the active + tab", and switching tabs felt like the whole right column + just reshuffled. The card lives on the same white-with-soft- + border pattern as `.agent-model-row` so the two BYOK / CLI + panels feel like the same family. + */ +

{API_PROTOCOL_LABELS[apiProtocol]}

@@ -2513,12 +2675,6 @@ export function SettingsDialog({ {activeSection === 'language' ? (
-
-
-

{t('settings.language')}

-

{t('settings.languageHint')}

-
-
{LOCALES.map((code) => { const active = locale === code; @@ -2569,7 +2725,7 @@ export function SettingsDialog({ {activeSection === 'memory' ? ( <> -
+

{t('settings.customInstructionsTitle')}

@@ -2578,7 +2734,7 @@ export function SettingsDialog({