Skip to content

Dev 1.4.0 - #505

Draft
ujiro99 wants to merge 76 commits into
mainfrom
dev-1.4.0
Draft

ujiro99 wants to merge 76 commits into
mainfrom
dev-1.4.0

Conversation

@ujiro99

@ujiro99 ujiro99 commented Oct 20, 2026

Copy link
Copy Markdown
Owner

No description provided.

ujiro99 and others added 30 commits October 19, 2026 08:19
The selection text shared via session storage was not cleared on tab
switching, and tabs without the content script (e.g. chrome://) can't
record their selection. So a shortcut could run with a stale selection
from another tab instead of falling back to the clipboard.

Record the tab ID with the selection and use it only when it matches
the active tab. Also re-record the selection when a tab becomes visible.

Closes #498

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The hub only serves the e2e test page and static data files, so a CSS
framework brings no benefit. Replace Tailwind classes with plain CSS
(globals.css + CSS Modules) and shadcn/ui components with native
elements, keeping the test page DOM that e2e relies on unchanged.

Also add E2E_HUB_BASE_URL to route the deployed hub to a local build so
hub changes can be verified with e2e before deploying.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWGX774FR5iixzXqS7CMpU
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWGX774FR5iixzXqS7CMpU
- postcss-shadow-dom-properties: declare the initial values of
  @property-registered custom properties inside the stylesheet, since
  Chrome ignores @Property in shadow trees (needed by Tailwind CSS v4)
- findRemUsages: detect rem units, which follow the user's page root
  font-size inside the content script's Shadow DOM

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWGX774FR5iixzXqS7CMpU
- Use @tailwindcss/vite and move the theme from tailwind.config.js to
  CSS (@theme); replace tailwindcss-animate with tw-animate-css and
  update tailwind-merge to v3
- Redefine every rem-based token in px (--spacing: 4px, text, container,
  radius) so the content script UI doesn't follow the user's page root
  font-size, and fail the build if content script CSS contains rem
- Apply the Shadow DOM @Property fallback via PostCSS
- Rename utilities for v4 (shadow, rounded, outline-hidden, ...), add
  @reference to CSS modules using @apply, and restore v3 defaults
  (placeholder color, button cursor)
- Ignore 'Request context disposed' in the e2e hub route helper

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWGX774FR5iixzXqS7CMpU
…canning

- Use @theme inline for tokens that reference runtime CSS variables.
  With a plain @theme, --color-background was resolved on :root/:host,
  so the popup's per-element --background override (user styles) no
  longer changed bg-background (e2e E2E-72)
- Scan only src/ (excluding tests) for class names; plain text in docs
  generated unused rem-based utilities

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWGX774FR5iixzXqS7CMpU
Windows opened by the extension (e.g. the PageAction recorder) load the
deployed HTML because their navigation can't be intercepted; forwarding
its hashed assets to the local build returned 404 and broke the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWGX774FR5iixzXqS7CMpU
The shortcut handler judged the selection with the stored text, while
the content script ran the command with the selection in its tab. So
when the window lost focus with text selected, the stale selection was
used instead of the clipboard.

- The shortcut handler passes the selection it decided to the content
  script, and decides whether to use the clipboard only once.
- Rename allowClipboardFallback to selectionFromClipboard, and split
  UrlParam.useClipboard into selectionFromClipboard and
  clipboardForSteps. Whether to read the clipboard is derived by
  needsClipboard().
- Remove the re-check of an empty selection in actions and toUrl.
- Stop re-recording the selection on visibilitychange.

Refs #498

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Ipc.getTabId returns null instead of throwing when the tab ID can't be
  retrieved, so callers don't need their own error handling.
- The shortcut handler gets the active tab with getCurrentTab(), like the
  other places in the service worker.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…olation

- Declare `@layer properties` at the top of every CSS file that uses layers,
  so it stays the lowest-priority layer whatever the chunk injection order.
- Fail the build when no content script CSS could be checked for rem, and
  also detect uppercase REM and other root-relative units (rlh, rex, ...).
- Define breakpoints in px as in v3, so media queries don't follow the
  browser's default font-size setting.
- e2e: return the local 404 for missing hub pages instead of falling back to
  the deployed hub, and match the base path on a segment boundary.
- Fix a lint error in the cn() test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KWGX774FR5iixzXqS7CMpU
Keeping the selection in session storage raced with the asynchronous
writes and the clears on focus change. The shortcut handler now asks the
active tab for its current selection, and the tab reports whether the
window lost focus after the text was selected, so the clipboard is used
instead of a selection that may be older than it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The executor fills in the default, so actions no longer repeat it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s focus

A global shortcut can be pressed while another app has focus, and the
active tab of the last focused window still has the selection made
before the user switched apps.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…OnFocusChange

The setting only keeps the menu open across focus changes. Keeping the
selection for the shortcut let a selection older than the clipboard be
used.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ignoring the selection after the window lost focus didn't match what the
user sees in the page. The selection is now ignored only when another
app has focus at the time the shortcut is run.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
cmd2uuid derived a command ID from its content including the title, but
it is no longer called from the extension or the Hub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuHp872cRxjzMMEpMfPxeG
- Lower the minimum command title length from 3 to 2.
- Trim the title and collapse whitespace runs (including full-width
  spaces, tabs and newlines) into one ASCII space before validation,
  and save the normalized title. Matches the Hub's normalization.

Refs ujiro99/selection-command-hub#297

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuHp872cRxjzMMEpMfPxeG
Match the Hub's limit so a title accepted by the extension is not
rejected when shared.

Refs ujiro99/selection-command-hub#297

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuHp872cRxjzMMEpMfPxeG
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MuHp872cRxjzMMEpMfPxeG
Start a new onboarding experiment that compares the welcome-overlay flow
(variant C, now the control) with a simplified variant D. Variant letters
now name a UI pattern rather than a role, so the control is chosen per
experiment and C keeps meaning the same pattern it did in onboarding_v3.

The kill switch and the failed-assignment fallback both land on C. Variant
A is no longer assigned but stays in the type until its code is removed.

Add onboarding_v4 to the hub experiments config, keeping onboarding_v3 for
already-published builds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7m4SrJWH9ySfRuqRtDVg6
…ground

Variant D drops the "select -> command -> result" OnboardingRail from
Steps 1-3 and replaces the slate vignette with the welcome overlay's blue
radial glow, kept behind every step. The glow is extracted into
OnboardingGlow and mounted by both the overlay and the layout at the same
time, so the overlay fades out onto an identical, already-bloomed glow.

Variant differences are resolved once in getVariantUi() and exposed as
onboarding.ui, so steps check `ui.showRail` instead of variant letters.
Steps 1 and 2 keep extra room above the target text without the rail so
its callout does not overlap the explanation.

Add variant D shots to the onboarding screenshot spec and pin the other
shots to an explicit variant.

Refs #494

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H7m4SrJWH9ySfRuqRtDVg6
- 読み取り失敗時に最大3回まで再試行する
- Offscreenからの不正な応答をエラーとして扱う
- textareaにフォーカスできない場合はエラーにする
- 作成時の単一ドキュメント制約エラーでは既存ドキュメントを使う
- バックグラウンドタブで開く場合は実行元タブへエラーを通知する
- エラートーストとクリップボード読み取りの重複処理を共通化する

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ujiro99 and others added 12 commits October 22, 2026 10:48
Add a theme option (system / light / dark) and apply the resolved theme
via the data-sc-theme attribute: on the shadow host for the content
script, so that the `dark:` variant and the dark color tokens also match
through `:host()`. A dedicated attribute avoids collisions with a host
page's own `.dark` class.

Dark defaults are added for the popup menu, its tooltip and the
"Open in Tab" button. When any popup color is set in the user styles,
the popup keeps those colors (and the light defaults for the rest) in
both themes to avoid losing contrast.

The options and onboarding pages stay light until their hard-coded
colors are migrated.

Refs #495

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DvJ25jdbq4pvn4K8Wk7Mx
…mmand list

Show a CloudUpload icon with a badge on the share button when a shared
command has local edits not yet pushed to the Hub, and push the edits
on click. Commands without a content fingerprint count as unchanged.

Closes #507

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Apply the theme to the options page and add dark counterparts to its
hard-coded neutral colors. The `dark:` classes are added next to the
existing ones, so the light theme renders exactly as before.

Monochrome icons (generic glyphs, folder SVGs) are drawn in black and
vanished on dark backgrounds. In the dark theme they are now recolored
like the global icon color setting does, keeping favicons, brand icons
and icons excluded from recoloring as they are. This also applies to the
popup menu when no popup color is customized. The resolved theme is
shared through a context so that each icon does not load the settings.

Refs #495

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DvJ25jdbq4pvn4K8Wk7Mx
…hed edits

Use the CloudUpload icon for the new share action too, and give the
button a light red background and a red badge when a shared command
has unpushed local edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use an orange badge, background and hover stroke instead of red, so the
state is not confused with an error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Derive the share state once and reuse it for icon, test id and tooltip
- Add aria-label to the share button and hide the badge from screen readers
- Drop the unused pending status in the push flow
- Add tests for push failure, repeated clicks and fingerprint stability
  through the form schema; fix the SB-06 test name

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(extension): 共有済みでローカル変更があるコマンドの同期ボタンを更新ありの表示にする
Apply the theme to the onboarding page and add dark counterparts to its
hard-coded colors next to the existing ones, so the light theme renders
as before. The brand color (sky-950) gets a lighter shade that keeps
buttons and progress pills visible on the dark background.

The logo image has dark text on a transparent background, so a dark
variant (wordmark lightness inverted, hue and icon kept) is added and
chosen by theme. The page background uses the same token as the options
page.

Refs #495

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DvJ25jdbq4pvn4K8Wk7Mx
@claude

claude Bot commented Oct 22, 2026

Copy link
Copy Markdown

レビュー結果(Dev 1.4.0)

196 ファイル / +5782 −3677 と大規模なため、新規・影響の大きいロジック(offscreen clipboard、PostCSS プラグイン、manifest プラグイン、shared uuid、manifest.json)を中心に確認しました。全体として設計意図がコメントで丁寧に説明されており、テストも追加されています。以下は指摘事項です。

要確認・バグの可能性

  1. packages/extension/src/lib/vite-plugin-manifest.ts:64-103 — assertNoRemInCss が dev/watch ビルドで失敗する恐れ
    content_scripts が無い場合に throw するよう変更され(L69)、その後 contentScriptCssFiles.length === 0 なら必ず例外になります(L103、assertNoRemInCss 内)。writeBundle が yarn dev(crxjs の dev/watch)でも呼ばれる場合、CSS が manifest に含まれないケースでビルドが落ちます。yarn dev と yarn build:e2e で動作確認をお願いします。必要なら production ビルド時のみ検査する(config.command === "build" 等)ことを検討してください。
    また L97-99 の catch は console.error のみで握りつぶすため、manifest 処理失敗の原因が「rem 検出失敗」という別メッセージに隠れます。エラーを保持して assertNoRemInCss のメッセージに含めると原因追跡しやすくなります。

  2. packages/extension/src/lib/vite-plugin-manifest.ts:6-17 — コメントの位置ずれ
    injectContentScriptCssFiles の説明コメント(L6-12)の直後に assertNoRemInCss の説明が連結されており、前者のコメントが injectContentScriptCssFiles から離れています。assertNoRemInCss のコメントを関数直前へ分離してください。

  3. packages/extension/src/lib/postcss-shadow-dom-properties.ts:70 — root.prepend の @layer 位置
    @charset / @import を含むスタイルシートでは、先頭に @layer を挿入すると @import が無効になる(@import は @charset と @layer 宣言以外より前に置く必要がある)可能性があります。現状 Tailwind v4 の出力で問題がないか、@import を含む CSS でのテストを 1 件追加すると安心です。

  4. packages/extension/src/services/offscreenClipboard.ts:33 — エラーメッセージ文字列への依存
    /single offscreen document/i で既存ドキュメントを判定していますが、Chrome のメッセージ変更に弱いです。失敗時にもう一度 getContexts で存在確認する方が堅牢です。また readWithRetry は権限エラーなど恒久的エラーも 3 回リトライします(遅延 50ms なので影響は小さい)。

  5. packages/extension/manifest.json — 権限とバージョン

    • offscreen 権限追加と minimum_chrome_version: "116" は offscreen API(Chrome 109+、getContexts は 116+)に整合しています。ただし clipboardRead を残している点は execCommand("paste") に必要なため妥当です。ストア審査向けに justification(offscreen_clipboard.ts の理由文)が十分か確認してください。
    • version が 1.3.2 のままです。ブランチ名 dev-1.4.0 なので、リリース前に更新が必要か確認してください。

軽微・改善提案

  • packages/extension/src/offscreen_clipboard.ts:13 — document.getElementById("clipboard") as HTMLTextAreaElement が null の場合、try の外で textarea.value を触る finally が TypeError になります。null チェックを try の前に入れてください(finally 内の参照が別例外を生みます)。
  • packages/extension/src/offscreen_clipboard.ts:4-8 — sender.id 検証は良いですが、return false で同期応答しているので問題ありません。ただしクリップボード内容がメモリ上に残らないよう finally で空にしている点は良い対応です。
  • packages/shared/src/utils/uuid.ts — cmd2uuid の削除は、リポジトリ内に参照が無いことを確認済みです(旧 hub 側のみで使用されていたため)。shared の公開 API 削除なので、CHANGELOG/リリースノートに記載しておくと良いです。
  • .claude/skills/check-japanese-in-src/ の削除 — AGENTS.md では「コード内コメントは英語」とされており、このチェック用スキルを削除する理由(別の仕組みへ移行したか)を PR 説明に書いてください。
  • PR の説明(body)が空です。Tailwind v4 移行、onboarding ABテスト、offscreen clipboard、hub 縮小など複数テーマが混在しているため、概要と動作確認項目(特に Shadow DOM での shadow/ring/transform/gradient の見た目、rem 不使用の確認)を記載してください。

パフォーマンス / セキュリティ

  • 重大な問題は見つかりませんでした。offscreen ドキュメントを再利用し、読み取りを直列化している点(offscreenClipboard.ts:67-71)は適切です。
  • 依存関係更新(Radix、tailwind-merge 3.x、Tailwind 4)は見た目の回帰リスクがあるため、yarn test / yarn build / e2e の結果(CI)を確認のうえマージしてください。

テスト

  • offscreenClipboard、postcss プラグイン、findRemUsages、onboarding 実験など新規ロジックにテストが追加されており良好です。
  • 追加推奨: vite-plugin-manifest.ts の assertNoRemInCss(空リスト時の失敗・rem 検出時の失敗)と、offscreen_clipboard.ts のメッセージハンドラ(フォーカス失敗/paste 失敗)のユニットテスト。

※ 差分全体(特に UI コンポーネントのスタイル変更)を網羅的には確認していません。

ujiro99 and others added 3 commits October 22, 2026 14:09
Use chrome.runtime.openOptionsPage() for the action icon click and the
openOption command so an already opened options page in the current
window is activated instead of opening a duplicate tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
"Update & share" stored the edited command through the debounced form
save while the service worker pushed it to the Hub in parallel. When the
Hub acknowledged first, the content fingerprint saved on the ack was
overwritten by the late form save with the old one, so the command list
showed the share button as having unpushed edits.

Save the form right away and wait for it before sending the command to
the Hub, both for "update & share" and for edits opened from the Hub.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019DvJ25jdbq4pvn4K8Wk7Mx
…terized URLs

Replace chrome.runtime.openOptionsPage() with an openOptionPage() helper
that searches all windows for an existing options page tab, and use it
for the action icon, the openOption command, adding/editing page rules,
and editing a command from the Hub. When a query is given, the existing
tab is navigated to it so the target dialog opens.

When the Hub edit reuses an existing tab, the tab is kept open after the
edit instead of being closed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ujiro99
ujiro99 marked this pull request as draft October 23, 2026 02:13
ujiro99 and others added 13 commits October 23, 2026 11:14
- Match options page tabs that are still loading via pendingUrl
- Prefer the options page tab in the last focused window
- Do not reuse the edit tab of a cancelled Hub edit session
- Catch errors from openOptionPage() in the service worker
- Update stale comments on reading location.search
- Await the opened tab in tests instead of a fixed number of ticks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(extension): reuse existing options page tab when opening settings
…-race

# Conflicts:
#	packages/extension/src/components/option/editor/CommandList.tsx

Co-authored-by: ujiro99 <677231+ujiro99@users.noreply.github.com>
fix(extension): 「更新&共有」後に ShareButton が「更新あり」と誤表示される問題を修正
feat(extension): テーマ設定の追加とポップアップのダークモード対応
# Conflicts:
#	packages/extension/src/components/option/ShareButton.tsx
- Exclude recolor from OptionMenuImage props since the theme decides it
- Draw StorageUsage legend swatches from BAR_COLORS to keep one source
- Derive the dark popup icon color from the font color variable
- Remove the theme attribute on useTheme cleanup
- Note that themeContext falls back to light outside a provider
- Extract usesIconColor from Popup and cover it with tests

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(extension): オプション画面のダークモード対応
- Paint the dark background from inline styles in onboarding_page.html
  and options_page.html, before scripts and styles load
- Apply data-sc-theme in a layout effect so the first paint already uses
  the dark styles
- Fix the noscript message typo in options_page.html

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Match the callout arrow fill to the callout body in dark mode
- Use a darker selection demo highlight in dark mode so the light text
  stays readable
- Brighten the "click anywhere" indicator in dark mode

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
feat(extension): オンボーディング画面のダークモード対応

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants