← Commit history
README.md+8−3
@@ -15,9 +15,13 @@ issue. The left column holds the **item ref** (`page #N`) with its colored status beneath; the right column holds the **description** with the **View link |'d at its end**, then `Created by <name> on <date> <time>`, `<Event> by <name> on <date> <time>` (Opened / Commented / Closed /-Reopened / Mentioned), and **your involvement** - "Drew opened this",-"Drew was mentioned", "Drew watches this page" - parsed from the mail's-"You're receiving this because..." footer. New activity bubbles to the top.+Reopened / Mentioned), and **your involvement** - "Drew owns this fix"+(assigned) > "Drew opened this" > "Drew owns this page" (you authored the+wiki page, looked up via `adom-wiki page stats`) > "Drew was mentioned" /+"commented on this" > "Drew watches this page" - from the mail's+"You're receiving this because..." footer plus page authorship. Set+`fullName` in the config (e.g. "Drew Owens") for the ownership check; it is+otherwise derived from the notification's To header. New activity bubbles to the top. (Chat cards have no native table widget: the columns widget caps at 2 and grid tiles are equal-width and unreadable, so the table is this 2-column layout; set `"style": "blocks"` for the compact per-item layout with View@@ -110,6 +114,7 @@ inbox. A failed board post never sweeps the email; it retries next pass. | `boardTitle` | `Wiki Notifications` | card header | | `style` | `table` | `table` (item ref + status left, details right, divider-ruled rows) or `blocks` (per-item blocks with View buttons) | | `meName` | `You` | your first name, used in the involvement line ("Drew opened this") |+| `fullName` | auto (To header) | your wiki author name (e.g. "Drew Owens"), used to detect pages you authored |  ## Commands 
bin/__pycache__/wiki-notify-gchatcpython-312.pyc
⋯ 1 unchanged line ⋯
bin/wiki-notify-gchat+39−2
@@ -45,6 +45,8 @@ DEFAULT_CONFIG = {     "maxRows": 40,     "boardTitle": "Wiki Notifications",     "style": "table",+    "meName": "You",+    "fullName": "", }  OPEN_COLOR, CLOSED_COLOR = "#22c55e", "#94a3b8"@@ -184,6 +186,31 @@ EVENT_PATTERNS = [ ]  +def page_author(page, state):+    """Author of a wiki page via `adom-wiki page stats` (cached in state)."""+    cache = state.setdefault("pageAuthors", {})+    if page in cache:+        return cache[page]+    author = ""+    code, out, _ = run_cmd(["adom-wiki", "page", "stats", page, "--json"])+    if code == 0:+        try:+            j = json.loads(out)+            author = ((j.get("data", j) or {}).get("page") or {}).get("author_name") or ""+        except Exception:+            pass+    cache[page] = author+    save_state(state)+    return author+++def annotate_page_ownership(state, me_full):+    """Mark items whose wiki page the user authored (drives 'owns this page')."""+    for it in state.get("items", {}).values():+        author = page_author(it["page"], state)+        it["ownsPage"] = bool(me_full) and author == me_full++ def parse_notification(msg):     """Return an event dict for a wiki notification email, or None."""     import html@@ -362,8 +389,11 @@ def render_table_widgets(shown, tz, me="You"):             dim(f"Created by {creator} on {fmt_datetime(it['openedAt'], tz)}"),             dim(f"{event} by {actor} on {fmt_datetime(it['lastAt'], tz)}"),         ]-        if it.get("invLabel"):-            fields.append(dim(f"{me} {it['invLabel']}"))+        inv = it.get("invLabel", "")+        if it.get("ownsPage") and it.get("invRank", 0) < 3:+            inv = "owns this page"  # page authorship beats mention/comment/watch, not opened/assigned+        if inv:+            fields.append(dim(f"{me} {inv}"))         widgets.append({"columns": {"columnItems": [             {"horizontalSizeStyle": "FILL_MINIMUM_SPACE", "verticalAlignment": "TOP",              "widgets": [{"textParagraph": {"text": f"<b>{item}</b><br>{status}"}}]},@@ -477,6 +507,10 @@ def ingest(cfg, state, query, sweep_mail=True, dry_run=False):                 if not ev:                     skipped += 1                     continue+                if not state.get("meFullName"):+                    tm = re.match(r'\s*"?([^"<]+?)"?\s*<', headers_of(msg).get("to", ""))+                    if tm:+                        state["meFullName"] = tm.group(1).strip()                 if not dry_run:                     apply_event(state["items"], ev)                     if sweep_mail:@@ -565,6 +599,7 @@ def cmd_run(as_json, dry_run=False, quiet=False):     board_changed = False     if not dry_run:         try:+            annotate_page_ownership(state, cfg.get("fullName") or state.get("meFullName", ""))             board_changed = push_board(cfg, state)         except Exception as e:             errors.append(f"board: {e}")@@ -598,6 +633,7 @@ def cmd_backfill(as_json, days=30, dry_run=False):     board_changed = False     if not dry_run:         try:+            annotate_page_ownership(state, cfg.get("fullName") or state.get("meFullName", ""))             board_changed = push_board(cfg, state)         except Exception as e:             errors.append(f"board: {e}")@@ -623,6 +659,7 @@ def cmd_board(as_json, dry_run=False):         card = render_card(state["items"], cfg)         print(json.dumps(card, indent=2)[:6000])         return+    annotate_page_ownership(state, cfg.get("fullName") or state.get("meFullName", ""))     changed = push_board(cfg, state, force=True)     emit(f"OK: board {'reposted' if changed else 'unchanged'} ({len(state['items'])} item(s)).") 
docs/board.png
⋯ 1 unchanged line ⋯
docs/hero.png
⋯ 1 unchanged line ⋯
package.json+1−1
@@ -2,7 +2,7 @@   "slug": "wiki-notify-gchat",   "title": "Wiki Notify for Google Chat",   "type": "app",-  "version": "1.2.0",+  "version": "1.2.1",   "description": "Turn wiki.adom.inc notification emails into a live Google Chat board. One card, one row per issue - newest first, OPEN/CLOSED status, origination date, actor, and a View link - continuously updated in your own Chat space via your own webhook. Emails are swept out of your inbox (trash, archive, or label). Closed items linger until 6am the next day, then drop off. Delegates all auth to adom-google; the only secret is your webhook URL, kept in your private config.",   "tags": [     "cli",
page.json+1−1
@@ -2,7 +2,7 @@   "slug": "wiki-notify-gchat",   "title": "Wiki Notify for Google Chat",   "type": "app",-  "version": "1.2.0",+  "version": "1.2.1",   "description": "Turn wiki.adom.inc notification emails into a live Google Chat board. One card, one row per issue - newest first, OPEN/CLOSED status, origination date, actor, and a View link - continuously updated in your own Chat space via your own webhook. Emails are swept out of your inbox (trash, archive, or label). Closed items linger until 6am the next day, then drop off. Delegates all auth to adom-google; the only secret is your webhook URL, kept in your private config.",   "tags": [     "cli",