You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
***save-modal:** break circular import to console-crane store ([ab00130](https://github.com/codebridger/subturtle-extension-apps/commit/ab00130647d72703147f8a96df6faa8e3b1fbbe5))
7
+
***save-modal:** refetch bundle options so post-save chip shows title ([25499da](https://github.com/codebridger/subturtle-extension-apps/commit/25499da35925bebeb854f20973c3ae39b4dbd6f2))
8
+
9
+
10
+
### Features
11
+
12
+
* announce extension presence on dashboard origins for install nudge [#86](https://github.com/codebridger/subturtle-extension-apps/issues/86)exkh0z3 ([69dcf1b](https://github.com/codebridger/subturtle-extension-apps/commit/69dcf1bc0c13f293c01592545ec2ccb1111d5f3e)), closes [#86exkh0z3](https://github.com/codebridger/subturtle-extension-apps/issues/86exkh0z3)
13
+
***console-crane:** practice + flashcard-preview pages, near-translation actions ([224b9da](https://github.com/codebridger/subturtle-extension-apps/commit/224b9da79e8b9d2f094ae3f63b1f8524fcb78299))
***practice-now:** open config to logged-out users + clearer CTAs ([2f09e05](https://github.com/codebridger/subturtle-extension-apps/commit/2f09e0577de43a55d995e9277446d313b058beef))
***save-modal:** chunk highlights, AI advice chat, bundle suggestion ([9954c22](https://github.com/codebridger/subturtle-extension-apps/commit/9954c22f8822f5a06912247d0098d937c20ec6b5))
18
+
***save-modal:** in-field bundle chips with dirty-aware save + inline removal ([374cbb4](https://github.com/codebridger/subturtle-extension-apps/commit/374cbb4b0c957c5def27d6b9f0211b3ed4fe17f5))
19
+
***save-modal:** per-chunk definitions, merged pronunciation, reorder save ([f766040](https://github.com/codebridger/subturtle-extension-apps/commit/f76604023886a6d88b18831c9e492ef8253e11b7))
20
+
***saved-phrase:** DB-first lookup, reuse stored translation, no AI re-call ([1315cc8](https://github.com/codebridger/subturtle-extension-apps/commit/1315cc86c3421ab64560e68e70d0b282c662d3ba))
Copy file name to clipboardExpand all lines: CLAUDE.md
+127-1Lines changed: 127 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -141,6 +141,7 @@ And the `SettingsObject` type in [src/common/types/messaging.ts](src/common/type
141
141
-**The mount root in Nibble must not block the page.** Set `width: 0; height: 0; position: fixed; top: 0; left: 0`. Children use their own `position: fixed` to position themselves relative to the viewport.
142
142
-**Theme dark class lives on `.subturtle-scope`, not `<html>`.** Tailwind's `dark:` rules are rewritten by `postcss-prefix-selector` to `.subturtle-scope.dark ...` — so the same element must carry both classes. The settings store handles this and a `MutationObserver` keeps Vue Teleport subtrees in sync.
143
143
-**`src/stores/profile.ts` imports types from a sibling repo.** The path `../../../dashboard-app/frontend/types/database.type` resolves to a directory _next to_ this repo's root, not inside it. The actual repo is [`codebridger/subturtle-dashboard-app`](https://github.com/codebridger/subturtle-dashboard-app); local builds work because devs check both repos out side-by-side. CI clones the dashboard repo into `../dashboard-app/` before `yarn build` runs (see [.github/workflows/release.yml](.github/workflows/release.yml)). Don't try to "fix" the import to a relative-internal path or vendor the file — both will drift.
144
+
-**Playwright Chromium download isn't on CCW's Trusted allowlist.** The chrome-extension-tester-mcp's `postinstall` runs `playwright install chromium`, which pulls from `cdn.playwright.dev` / `playwright.download.prss.microsoft.com`. CCW environments must use Custom network access with those hosts added — see [§ Cloud agent workflow](#cloud-agent-workflow-claude-code-on-the-web). The setup script caches Chromium into the VM snapshot so per-session cost is zero.
nibble-flow.spec.ts # content script mounting + Persian emitOpen
321
324
console-crane-lifecycle.spec.ts # modal stays open while Nibble toggles off
322
325
translate-flow.spec.ts # full Persian translate-and-save with page.route stubs
326
+
password-login.spec.ts # popup password form end-to-end with stubbed /user/login
323
327
visual-scale.spec.ts # rem→px rewrite regression net
324
328
```
325
329
326
330
### Test totals
327
331
328
-
79 unit / component tests across 9 files; 11 E2E specs across 5 files. Full suite runs in ~15s once Playwright's Chromium is warm.
332
+
138 unit / component tests across 19 files; 16 E2E specs across 6 files. Full suite runs in ~20s once Playwright's Chromium is warm.
333
+
334
+
## Cloud agent workflow (Claude Code on the Web)
335
+
336
+
Lets a cloud Claude agent on [Claude Code on the Web (CCW)](https://code.claude.com/docs/en/web-quickstart) clone the repo, build the extension, install it into a headless Chromium, log in with username/password against the live dev server at `https://dev.dashboard.subturtle.app/`, and drive popup + content scripts with screenshots — no Google OAuth, no local backend.
337
+
338
+
The agent path uses **only** the [chrome-extension-tester-mcp](https://github.com/BHUVAN-RJ/chrome-extension-testing-mcp) MCP server (declared in [.mcp.json](.mcp.json)). It is independent of the `tests/e2e/` Playwright fixture and shares no code with it; CI verify runs the spec, the agent runs the MCP.
339
+
340
+
### One-time CCW environment setup
341
+
342
+
Done once per CCW environment from [claude.ai/code](https://claude.ai/code) — these settings live in the cloud UI, not the repo.
343
+
344
+
**Network access:**`Custom`, keeping the Trusted defaults plus Playwright's Chromium-download hosts. Without these, the setup script's `npm install -g chrome-extension-tester-mcp` hangs while pulling Chromium:
345
+
```
346
+
cdn.playwright.dev
347
+
playwright.download.prss.microsoft.com
348
+
```
349
+
350
+
**Environment variables** (`.env` format, no quotes):
`AGENT_EMAIL` / `AGENT_PASSWORD` are not consumed by the build — they exist so the agent's Bash step can reference `$AGENT_EMAIL` / `$AGENT_PASSWORD` without hardcoding into the prompt. They must match an account that exists on the dev server (the agent does not register; the human or dashboard team seeds the account).
367
+
368
+
**Setup script** (runs as root on Ubuntu 24.04, cached as a VM snapshot — first session ~5 min, subsequent ones reuse the cache):
369
+
```bash
370
+
#!/bin/bash
371
+
set -e
372
+
373
+
cd"${CLAUDE_PROJECT_DIR:-/workspace}"
374
+
375
+
# 1. Install extension deps.
376
+
yarn install --frozen-lockfile
377
+
378
+
# 2. Materialize .env.production from CCW env vars (dotenv-webpack's safe:true
379
+
# requires every key in .env.example to be present at build time).
# 4. Install the MCP globally so Playwright Chromium is downloaded once
396
+
# into the cached snapshot. npx in .mcp.json resolves to this install.
397
+
npm install -g chrome-extension-tester-mcp@^2.1
398
+
```
399
+
400
+
### Driving the extension via the MCP
401
+
402
+
Once the environment is set up and the agent session starts, the cached snapshot already has `dist/` built and Playwright Chromium installed. The full login + screenshot loop becomes:
403
+
404
+
```
405
+
# 1. Load the unpacked extension into headless Chromium.
406
+
load_extension({ extension_path: "$PWD/dist" })
407
+
408
+
# 2. Get a JWT from the dev server with the credentials in CCW env vars.
409
+
# modular-rest's authentication.login POSTs to /user/login.
410
+
# The password MUST be base64-encoded — modular-rest's client library
411
+
# does this internally, but raw curl has to pre-encode. Without it
412
+
# the server returns HTTP 412 {"status":"error","e":{}}.
# Expected: "Logged In Successfully!" view (LoginView.vue:57-68 v-else branch).
427
+
```
428
+
429
+
The MCP exposes 14 tools — others worth knowing about: `inspect_dom` (eval JS in a page), `monitor_network` (capture requests during navigation), `send_message_to_background` (drive `chrome.runtime.onMessage` listeners), `get_service_worker_logs` (read background SW console output), `run_assertion` (returns structured PASS/FAIL). Full reference: the [chrome-extension-tester-mcp README](https://github.com/BHUVAN-RJ/chrome-extension-testing-mcp).
430
+
431
+
### Why password auth exists in this build
432
+
433
+
`ENABLE_PASSWORD_AUTH` gates the email + password form in [src/popup/views/LoginView.vue](src/popup/views/LoginView.vue) at build time via `dotenv-webpack`. CCW builds set it true so the agent (or a human dev) can log in by typing credentials; stable + dev release builds in [.github/workflows/release.yml](.github/workflows/release.yml) set it false so production users see only Google OAuth. The agent's direct-API path doesn't need the UI, but the UI is what makes manual testing possible.
434
+
435
+
### How auth works under the hood
436
+
437
+
The agent's direct-API path POSTs `/user/login` (via `curl`) and gets a JWT. Injecting that JWT into `chrome.storage.sync["token"]` (via the MCP's `extension_storage` tool) lands it in the *same slot* the post-OAuth `StoreUserTokenMessage` path uses — see [src/background.ts:62](src/background.ts) for the read side. modular-rest's client, the profile store, the translate service, and ConsoleCrane all see no difference between an OAuth-issued token and a password-issued token.
438
+
439
+
### Local dev fallback (no CCW, no MCP)
440
+
441
+
```bash
442
+
echo"ENABLE_PASSWORD_AUTH=true">> .env.production # plus the other 8 keys
443
+
yarn build && yarn dev # webpack --watch
444
+
# Load dist/ at chrome://extensions, click the extension icon, use the form.
445
+
```
446
+
447
+
The popup form drives `authentication.login` from `@modular-rest/client`, hitting whatever `SUBTURTLE_API_URL` points at. No MCP, no Playwright — just the same UI a real user would see.
448
+
449
+
### Boundary
450
+
451
+
The agent path uses only the MCP. `tests/e2e/` is the testing ground for CI verify and stays untouched by agent tooling; the two never share code. If you need to add a new agent capability, route it through the MCP's tools or a new MCP — not through the Playwright fixture.
329
452
330
453
## Verification checklist
331
454
@@ -341,6 +464,7 @@ Automated:
341
464
- Per-host Nibble toggle persists and normalizes (`www.` strip, case fold, dedup). → [tests/settings-host.test.ts](tests/settings-host.test.ts).
342
465
- ConsoleCrane on Persian / CJK / emoji inputs throws no `InvalidCharacterError` from `btoa` — covered at the encode level, the bridge level, and the full select-and-save flow. → [tests/route-params.test.ts](tests/route-params.test.ts), [tests/e2e/nibble-flow.spec.ts](tests/e2e/nibble-flow.spec.ts), [tests/e2e/translate-flow.spec.ts](tests/e2e/translate-flow.spec.ts).
343
466
- Visual scale is consistent on default-html-fontsize and 24px-html-fontsize hosts (postcss `rem→px` rewrite regression net). → [tests/e2e/visual-scale.spec.ts](tests/e2e/visual-scale.spec.ts).
0 commit comments