# Result — 002 Planning

> اکشن مرتبط: [`action/002_action_planning.md`](../action/002_action_planning.md)
> تاریخ اجرا: 2026-06-09

---

## هدف این جلسه

خواندن پروژه، فهمیدن ساختار، و پیاده‌سازی گام اول MVP:
اتصال افزونه‌ی Chrome به یک سرور پایتون بیرون مرورگر از طریق WebSocket.

---

## تصمیم‌های کلیدی که گرفته شد

### معماری — چرا extension به‌عنوان WS client؟

افزونه نمی‌تواند خودش سرور باشد (MV3 سرویس‌ورکر TCP port نمی‌تواند باز کند).
پس **افزونه client است و پایتون server** — افزونه به `ws://127.0.0.1:8765` وصل می‌شود.

همچنین WS باید از service worker باز شود، نه content script؛ چون content script
تابع CSP صفحه‌ی گوگل میت است و `connect-src` اتصال را بلاک می‌کند.

### نقطه‌ی hook در کد افزونه

`setSpeaker()` در `storage.js` — هر پاراگراف caption نهایی از این تابع رد می‌شود.
یک `chrome.runtime.sendMessage` کوچک به آن اضافه شد که background را خبر می‌کند.

### venv برای پایتون

تصمیم گرفته شد پایتون داخل `.venv` اجرا شود تا سیستم کثیف نشود.

---

## چه چیزی ساخته شد

| فایل | نوع | کار |
|------|-----|-----|
| `bridge/server.py` | جدید | WebSocket server پایتون روی `127.0.0.1:8765` |
| `bridge/requirements.txt` | جدید | فقط `websockets>=12.0` |
| `bridge/.gitignore` | جدید | `.venv/` و `transcripts/` از git خارج |
| `bridge/README.md` | جدید | راهنمای اجرا با venv |
| `bridge/_smoke_test.py` | جدید | کلاینت تستی بدون Chrome |
| `bridge/.venv/` | جدید | محیط ایزوله پایتون |
| `google-meet-transcripts-extension/bridge.js` | جدید | WS client داخل service worker |
| `login.js` | ویرایش | اضافه شدن `importScripts("bridge.js")` |
| `storage.js` | ویرایش | `setSpeaker` حالا `TRANSCRIPT_UPDATE` می‌فرستد |
| `manifest.json` | ویرایش | `ws://127.0.0.1:8765/*` به `host_permissions` اضافه شد |

---

## تست انجام شده

سرور پایتون با `_smoke_test.py` end-to-end تست شد:
- PING → PONG ✅
- سه `TRANSCRIPT_UPDATE` → سه ACK ✅
- فایل `transcripts/meeting-abc123.txt` با متن فارسی درست ذخیره شد ✅

تست با Chrome واقعی هنوز انجام نشده (نیاز به Reload افزونه و یک جلسه‌ی Meet).

---

## وضعیت چک‌لیست اصلی (از action)

- [x] حذف کدهای laxis — **انجام شد** (اجرای ۲۰۲۶-۰۶-۱۰، پایین را ببین)
- [x] لوگوی اختصاصی — **انجام شد** (لوگوی جدید جایگزین شد)
- [x] گرفتن caption از افزونه — گام ۱ (اتصال) انجام شد
- [x] سرویس MCP روی پورت — **انجام شد** (روی همان `server.py`)
- [ ] تست میدانی با Chrome واقعی — باقی‌مانده (نیاز به مرورگر و یک جلسه‌ی Meet)

---

## اجرای دوم — پاک‌سازی laxis + MCP + لوگو (۲۰۲۶-۰۶-۱۰)

### پاک‌سازی laxis (هیچ داده‌ای دیگر بیرون نمی‌رود)

- `analytics.js`: کاملاً خالی شد (از قبل کامنت‌شده و مرده بود؛ در manifest هم لود نمی‌شد).
- `login.js` (service worker): بازنویسی شد — حذف `tabs.onRemoved` (که transcript را آپلود می‌کرد)،
  حذف `onMessageExternal` (دریافت توکن) و `getTopics`. فقط import ها + نگه‌داشتن وضعیت لوکال ماند.
- `runtime.js` (content script): حذف فراخوانی `addRemindLogin()` و کل listener دریافت توکن/fetch.
- `meetingInfo.js`: `checkToken` و `renewToken` با `return;` در ابتدا خنثی شدند؛ آپلود پایان جلسه
  (`Export2App` + باز کردن `domainUrl/transcript`) حذف شد.
- `transcript.js`: `Export2App` بلافاصله reject می‌کند (آپلود ابری قطع)، `getTopics` خنثی شد،
  `addRemindLogin` خالی شد، منوی دانلود از حالت پیش‌فرضِ «app/cloud» به دانلود محلی `txt` تغییر کرد.
- `panel/main.js`: لینک لوگو → `domainUrl/login` در هر سه جا حذف شد؛ متن‌های برند «Laxis…» حذف شدند.
- `manifest.json`: `update_url` فروشگاه حذف شد (که افزونه با ID لاکسیس آپدیت نشود)؛ name/description
  به نسخه‌ی محلی و بدون cloud تغییر کرد.

### MCP روی server.py

سرور حالا در یک پراسس هم WebSocket (برای افزونه) و هم MCP stdio (برای Claude) را اجرا می‌کند و
حافظه‌ی `sessions` را share می‌کنند. ابزارها: `list_sessions`، `get_transcript`،
`get_latest_transcript` و resource با الگوی `transcript://{session_id}`. کانفیگ Claude Desktop در
`bridge/README.md`.

### درس‌آموخته‌ها

- **stdout برای MCP رزرو است:** همه‌ی `print` ها به stderr منتقل شدند، وگرنه استریم JSON-RPC خراب می‌شود.
  برای تست دستیِ WebSocket باید از `python server.py --ws-only` استفاده کرد.
- **کد افزونه minified است:** برای فایل‌های فشرده (`meetingInfo.js`) به‌جای حذفِ بدنه‌ها، با `return;`
  در ابتدای تابع خنثی‌سازی شد (کم‌ریسک‌تر). کدِ مرده باقی می‌ماند ولی هرگز اجرا نمی‌شود.
- **یک رشته‌ی غیرفعال باقی‌ست:** متنِ «Autosave to Laxis cloud…» در `displayGoogleMeetQuota`
  (`transcript.js`) داخل کدِ مرده مانده — هرگز نمایش داده نمی‌شود چون فراخوان‌هایش خنثی‌اند.

### تأیید (validation)

- syntax همه‌ی فایل‌های JS با `node --check` پاس شد.
- منطق `server.py` با AST + یک smoke test واقعیِ WebSocket (PONG/ACK + ذخیره‌ی صحیح فارسی) تأیید شد.
- ابزار/resource های MCP با `mcp` SDK ساخته و اجرا شدند (`get_latest_transcript` متن را درست برگرداند).

### باقی‌مانده برای تو

تست میدانی: venv را بساز/فعال کن، `python server.py --ws-only` را اجرا کن، افزونه را در
`chrome://extensions` **Reload** کن، در یک Meet واقعی caption را روشن کن و خروجی را در
`bridge/transcripts/` ببین. بعد کانفیگ MCP را به Claude Desktop اضافه کن.
