← Back to PRs

#20838: feat(extensions): add google-keep plugin for reading unchecked list i…

by acs111 open 2026-02-19 10:36 View on GitHub →
size: M
…tems Adds a new bundled extension that uses a Playwright persistent browser context to fetch unchecked items from a shared Google Keep note. - `google_keep_list` agent tool: navigates to a Keep note URL and returns unchecked items via aria-attribute DOM queries - `KeepSession`: lazily launches a headless Chromium context; profile stored at `<stateDir>/plugins/google-keep/profile/` - `/keep login` command: opens a visible browser for Google auth and auto-closes once login completes - `KeepAuthError` raised when navigation lands on an accounts.google.com URL, with an actionable message pointing to `/keep login` - Plugin config supports `listUrl`, `profileDir`, and `timeoutMs` ## Summary - Adds a new `google-keep` bundled extension that uses a Playwright persistent browser context to fetch unchecked items from a shared Google Keep list note - Registers a `google_keep_list` agent tool with optional `listUrl` and `limit` parameters; falls back to `pluginConfig.listUrl` - `KeepSession` lazily launches a headless Chromium context with profile stored at `<stateDir>/plugins/google-keep/profile/` for session persistence across restarts - `/keep login` command opens a visible browser for Google OAuth and auto-closes once login completes - `KeepAuthError` raised with an actionable message when navigation lands on `accounts.google.com` - Plugin config supports `listUrl`, `profileDir`, and `timeoutMs` ## Bug fixes (post-review) - **Race condition in `getPage()`** — concurrent calls now coalesce into a single launch promise instead of spawning multiple browser processes - **`isAuthUrl()` false positives** — replaced substring match with `new URL(url).hostname` check to avoid matching `/signin` anywhere in a URL - **SPA stale content** — switched `goto` to `waitUntil: "load"` and added a note-container wait before querying checkboxes, preventing items from a previous note being returned on SPA navigation - **Hardcoded 8s timeout** — `extractUncheckedItems` now accepts and uses `timeoutMs` from plugin config for both `waitForSelector` calls - **Login context not tracked** — `openLoginBrowser` stores the visible browser in `this.loginContext`; `getPage()` throws if login is in progress; cleanup is owned by the returned `done` promise - **`/keep status` no-op** — now checks `fs.existsSync(profileDir)` and reports actual session state ## Test plan - [ ] Enable plugin: `openclaw plugins enable google-keep` - [ ] Run `/keep login` — confirm browser opens at `keep.google.com` - [ ] Run `/keep status` before login — confirm "Not authenticated" message - [ ] Sign in to Google, confirm browser closes automatically - [ ] Run `/keep status` after login — confirm "Authenticated" message with profile path - [ ] Invoke `google_keep_list` tool with a Keep note URL — confirm unchecked items returned as JSON - [ ] Invoke with `limit` parameter — confirm result is capped - [ ] Invoke while `/keep login` browser is open — confirm descriptive error is returned - [ ] Call tool concurrently — confirm only one browser process launches - [ ] Restart gateway — confirm session is reused from saved profile (no re-login required) - [ ] Invoke without `listUrl` param or config — confirm descriptive error is returned - [ ] Invoke when not logged in — confirm `KeepAuthError` with `/keep login` hint

Most Similar PRs