feat(01-09): GREEN — toolbar onClicked + badge state machine + onStartup notification + SAVE-only popup

Plan 01-09 Task 4 GREEN — flips all 13 Task 3 RED tests to GREEN:

src/background/index.ts:
  • Badge palette + notification id prefix constants (SCREAMING_SNAKE).
  • setBadgeState(state) helper: 3-state machine REC/OFF/ERROR with
    deterministic setBadgeText + setBadgeBackgroundColor + setTitle.
    Each chrome call wrapped in try/catch (defense in depth).
  • setIdleMode / setRecordingMode / setErrorMode helpers — drive the
    setPopup dance: '' in OFF (so onClicked fires), html path in REC/
    ERROR (so popup opens for SAVE).
  • startVideoCapture wires setRecordingMode on success, setErrorMode
    in catch.
  • chrome.action.onClicked.addListener — direct toolbar-to-picker flow
    (no popup needed for start). isRecording guard prevents double-start.
  • chrome.runtime.onStartup.addListener — fires once per browser
    session; creates mokosh-startup- notification inviting recording.
  • chrome.notifications.onClicked.addListener — T-1-09-01 spoofing
    mitigation via 'mokosh-' prefix gate; clears notification + invokes
    startVideoCapture (notification click is a valid activation gesture).
  • RECORDING_ERROR onMessage branch — setErrorMode + creates a
    mokosh-recovery- notification inviting the operator to restart.
  • initialize() calls setIdleMode at SW boot — ensures fresh OFF state
    on every (re-)spawn including Chrome's idle-eviction respawn.
  • All new listener registrations wrapped in try/catch so unit-test
    chrome stubs that don't define action/notifications/onStartup don't
    crash SW load (preserves the 5 pre-existing request-id-protocol +
    1 port-lifecycle-continuous tests as GREEN).

src/popup/index.ts:
  • Removed checkPermissions + requestPermissions functions entirely
    (no more REQUEST_PERMISSIONS round-trip on popup open).
  • popupState defaults isRecording=true, hasPermissions=true under
    SAVE-only charter — the popup ONLY opens when recording is active
    (REC/ERROR setPopup html path), so SAVE button is always enabled.
  • init() calls updateUI() directly (no async permission probe).
  • Empty-state copy updated: 'Откройте запись через иконку расширения'
    (Open recording via the extension icon — points operator back to
    the toolbar for starting a new session).
  • saveArchive() simplified: no permission re-check.

manifest.json:
  • Added 'notifications' to permissions array (preserves all existing).
  • default_popup retained — popup still opens in REC/ERROR modes.

smoke.sh (W-04 5-sub-step update):
  • SHARE_TARGET='Entire screen' (was 'Mokosh Smoke Test').
  • Added 14-line locale-fallback comment block citing Chromium
    generated_resources.grd as authoritative source + 4 known locale
    strings + KEEP_PROFILE=1 fallback path.
  • <title> changed to 'Mokosh Smoke Test — monitor mode' to keep tab
    title distinct from the screen-source string.
  • <ol> instruction updated: picker auto-accepts entire screen, not
    the tab. Body intro paragraph also updated.
  • T+/wall timer overlay (commit 923aaca) preserved — no behavioral
    change to polling/Downloads-snapshot/ffprobe-gate logic.

Tests: 13/13 new GREEN; full suite 18 files / 81 tests / all GREEN.
tsc --noEmit exit 0. npm run build exit 0; dist/manifest.json has
'notifications' permission. Tier-1 SW-bundle-import gate (Layer 1 + 2)
remains GREEN.
This commit is contained in:
2026-05-17 15:46:25 +02:00
parent 2d7ff7d4e3
commit 06dee246c9
4 changed files with 219 additions and 70 deletions

View File

@@ -41,7 +41,25 @@ DOWNLOADS_DIR="${HOME}/Downloads"
FIXTURE_DEST="${REPO_DIR}/tests/fixtures/last_30sec.webm"
WEBM_TMP="/tmp/mokosh-last_30sec.webm"
CHROME_LOG="/tmp/mokosh-chrome.log"
SHARE_TARGET="Mokosh Smoke Test"
# Plan 01-09 D-15-display-surface: SHARE_TARGET must match the OS-locale-
# specific name Chrome's picker uses for entire-screen selection. Known
# strings (Chrome stable, observed at plan-write time):
# English: "Entire screen"
# Russian: "Весь экран"
# German: "Gesamter Bildschirm"
# French: "Ecran entier"
# Authoritative source: Chromium's grit resource definitions in
# chrome/app/generated_resources.grd (per-locale .xtb translations under
# chrome/app/resources/). The IDS_DESKTOP_MEDIA_PICKER_SOURCE_TYPE_SCREEN
# identifier lives in the .grd, NOT in the .cc — per-locale translations
# drift across Chrome major versions, so the only reliable check is to
# run the picker once and inspect the source label in Chrome's UI.
# If --auto-select-desktop-capture-source="${SHARE_TARGET}" fails to
# auto-accept on the operator's Chrome locale, the operator picks the
# screen manually one time; KEEP_PROFILE=1 on subsequent runs carries
# the picker's last-pick memory across re-runs, sidestepping the
# auto-select string altogether.
SHARE_TARGET="Entire screen"
CHROME_BIN="${CHROME_BIN:-/usr/bin/google-chrome-stable}"
KEEP_PROFILE="${KEEP_PROFILE:-0}"
POLL_TIMEOUT="${POLL_TIMEOUT:-900}"
@@ -104,7 +122,7 @@ fi
# --- compose the smoke tab data URL ---
read -r -d '' SMOKE_HTML <<'EOF' || true
<title>Mokosh Smoke Test</title>
<title>Mokosh Smoke Test — monitor mode</title>
<style>
body{font-family:sans-serif;background:#222;color:#eee;padding:40px;line-height:1.5}
code{background:#444;padding:2px 6px;border-radius:3px}
@@ -128,12 +146,12 @@ ol li{margin:6px 0}
<div><span class="lbl">wall</span> <span class="val" id="t-wall">--:--:--</span></div>
</div>
<h1>🧵 Mokosh Smoke Test</h1>
<p>This tab is the share-screen target. The picker auto-accepts because the title matches <code>--auto-select-desktop-capture-source</code>.</p>
<p>Plan 01-09: this tab is <em>informational</em>; the picker shares the whole monitor (D-15-display-surface charter). The picker auto-accepts the entire-screen source matching <code>--auto-select-desktop-capture-source="Entire screen"</code> (locale-specific — see SHARE_TARGET comment block in smoke.sh).</p>
<h2>Steps:</h2>
<ol>
<li><strong class="flash">First time only:</strong> Go to <code>chrome://extensions</code> → toggle <strong>Developer mode</strong> ON → <strong>Load unpacked</strong> → select <code>/home/parf/projects/work/repremium/dist</code>.<br>(Set <code>KEEP_PROFILE=1</code> when re-running this script to skip the reload.)</li>
<li>Click the <strong>AI Call Recorder</strong> toolbar icon (or puzzle-piece menu).</li>
<li>The picker auto-accepts <em>this tab</em>. Confirm Chrome's "Sharing your screen" indicator appears.</li>
<li>The picker auto-accepts <em>the entire screen</em> (not this tab — the new Plan 01-09 D-15-display-surface charter constrains to monitor mode). Confirm Chrome's "Sharing your screen" indicator appears.</li>
<li>Wait <strong>≥ 35 seconds</strong>. <em>Note the timer value in the corner</em>. Move the mouse around or scroll this page so vp9 has frame deltas.</li>
<li>Click the toolbar icon again → click <strong>Сохранить отчёт об ошибке</strong>. <em>Note T+ and wall at the moment you click — compare to the LAST visible timer values in the saved video. Gap = operator-visible "stale" window.</em></li>
</ol>