Skip to content

Add SOL Inbound Monologue RSS reader extension - #449

Merged
AllTerrainDeveloper merged 4 commits into
trunkfrom
feat/sol-im-feed-reader
Jul 31, 2026
Merged

Add SOL Inbound Monologue RSS reader extension#449
AllTerrainDeveloper merged 4 commits into
trunkfrom
feat/sol-im-feed-reader

Conversation

@nickhamze

@nickhamze nickhamze commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds SOL Inbound Monologue, a standalone Desktop Mode extension that presents RSS and Atom subscriptions as an inbound-only, turn-of-the-century buddy list and conversation reader.

  • Registers a movable/resizable buddy-list widget and a docked native reader window through the public Desktop Mode APIs.
  • Adds per-user subscriptions, groups, ordering, unread state, feed management, optional synthesized chimes, away/offline states, and a small SOL keyboard easter egg.
  • Updates the Playground/Studio Blueprint to install SOL, seed three real WordPress project feeds, and stage both surfaces automatically.
  • Adds enforceable extension checks to CI and makes the extension packager handle optional fetcher/vendor globs on macOS's bundled Bash.

Why

SOL is a useful extension in its own right and a fairly complete dogfood test for the public window, widget, shared-store, request, confirmation, theme-token, and <wpd-*> component APIs. It also gives the one-click demo an inhabited, immediately understandable extension surface without adding code to the core plugin.

Implementation notes

Feed and state boundary

  • Fetches feeds server-side with wp_safe_remote_get().
  • Restricts requests to public HTTP(S) URLs and relies on WordPress's unsafe-URL validation for the initial request and redirects.
  • Caps responses at 1 MiB, requests at 8 seconds and three redirects, normalized items at 50 per feed, subscriptions at 200 per user, and read-history IDs at 250 per feed.
  • Caches normalized feeds for ten minutes and rate-limits manual refreshes to once per feed every 30 seconds.
  • Parses already-fetched bytes with SimplePie network fetching disabled, supports RSS/Atom plus HTML autodiscovery, and renders only normalized text—no feed HTML or remote images.
  • Keeps subscriptions, preferences, refresh state, and unread state isolated in user meta.

Desktop integration and lifecycle

  • Uses stable IDs: feed-buddy-reader, feed-buddy/buddy-list, and feed-buddy/state.
  • Uses wp.desktop.fetch(), wp.desktop.confirm(), createSharedStore(), applyWindowTheme(), and native window channels instead of raw browser substitutes.
  • Uses Desktop Mode components for controls and status surfaces.
  • Aborts requests and clears polling intervals, timers, audio contexts, channel subscriptions, resize listeners, store listeners, dialogs, and themed-window overrides on teardown.

Accessibility and visual direction

  • Includes visible focus treatment, explicit online/offline text for assistive technology, non-color unread cues, polite status regions, reduced-motion behavior, forced-colors behavior, and a compact reader layout below 560 px.
  • Sound is original, synthesized at runtime, and off by default. No AOL/AIM marks, icons, recordings, or copied assets ship.
  • The Imagegen work is retained only as auditable direction evidence; production UI is live TypeScript/CSS with Dashicons and Desktop Mode components.

SOL Inbound Monologue messenger-first design direction

Testing

Repository gates:

  • npm run build
  • npm run lint
  • npm run typecheck
  • npm run test:js — 256 files, 2,499 tests
  • npm run test:php — 1,678 tests, 4,295 assertions, 3 skipped

SOL-specific gates:

  • extension ESLint, TypeScript, and production/development builds
  • Vitest — 2 files, 9 tests
  • PHPUnit — 13 tests, 64 assertions on PHP 8.3
  • PHPCS against the extension ruleset
  • PHP syntax checks
  • Blueprint JSON validated against the official Playground schema
  • all nine seeded WordPress.org article links verified live

Packaging/install verification:

  • ./bin/package-extensions.sh
  • archive integrity checked with unzip -t
  • confirmed no node_modules or nested dist tree is present
  • installed the generated ZIP into the isolated wp-env site and verified that it activates, registers its REST routes, and loads its Desktop Mode integration
  • final ZIP: 1,414,033 bytes; SHA-256 c564d7bf9503efe17116f73a23a345c30d847dcde68aeb207ab418c542281312

Reviewer QA

The normal PR preview exercises the core plugin but does not package standalone extensions. For SOL itself:

  1. Check out this branch and run npm ci.
  2. Run ./bin/package-extensions.sh.
  3. Start the normal local environment and activate Desktop Mode.
  4. Install and activate dist/desktop-mode-feed-buddy.zip as a separate plugin.
  5. Add the buddy-list widget, open SOL Inbound Monologue, add an RSS/Atom or website URL, switch feeds, mark entries read/unread, reorder and remove a feed, refresh, and toggle sound.
  6. Verify the compact reader layout, keyboard focus states, reduced motion, and forced-colors presentation.

The in-app browser's network policy blocked agent access to the localhost visual QA site. Package activation, registrations, feed behavior, and UI lifecycle are covered by the checks above; the selected visual evidence and its taste review are included under extensions/desktop-mode-feed-buddy/design/.

The committed Blueprint intentionally references trunk, so the one-click SOL demo becomes available after merge without leaving a feature-branch reference in the release configuration.

Open WordPress Playground Preview

nickhamze and others added 2 commits July 29, 2026 13:56
`<wpd-button>` and `<wpd-text-field>` render their native `<button>` and
`<input>` inside a shadow root, and form association does not cross a
shadow boundary. The submit button therefore had no form owner, so the
light-DOM `<form data-feed-buddy-add-form>` never received a `submit`
event: clicking "Add buddy" did nothing, and Enter in the URL field did
nothing either, since implicit submission also needs a form-owned
control. The whole add-feed path was unreachable.

Drive submission the way the component kit's own `<wpd-form>` does —
from the button's click and the field's `wpd-submit` event — keeping the
native `submit` listener as a fallback for plain controls. Guard against
a double-click firing two POSTs, and report an empty URL through the
existing status region instead of silently doing nothing.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sKW1mu1SGg5k9oSHgxv5s

@AllTerrainDeveloper AllTerrainDeveloper left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested it and this button was not working (add buddy)
Image

After fixing it it works beatifully
Image

I have one objection but of course that's very subjective. I'm not pretty sure if the transparent title bar works ok with light backgrounds in the wallpaper
Image

AllTerrainDeveloper and others added 2 commits July 31, 2026 12:55
Three fixes to the SOL Inbound Monologue surfaces.

The extension had no row in OS Settings -> Apps & Icons. That list is
built from the dock-item payload plus `desktop_mode_register_icon()`
registrations, and a native window with `placement => 'dock'` is
neither -- so there was no way to move SOL to the wallpaper or hide
it. Register the launcher icon alongside the window, the pattern the
other bundled extensions already follow. The shell dedupes the two,
so the dock does not paint the target twice.

The widget title bar rendered fully transparent. The palette was
scoped to `.feed-buddy-reader, .feed-buddy-widget`, but the shell's
chrome header is a sibling of the body slot `.feed-buddy-widget`
mounts into, not a descendant. Custom properties only inherit
downward, so `background: var(--feed-buddy-blue)` on the chrome was
invalid at computed-value time and fell back to its initial value --
the wallpaper showed through behind the correctly white title text.
The card background failed the same way. Add the widget card to the
palette's selector list and route the chrome through two named
tokens carrying the same values `applyReaderTheme()` installs as
`--desktop-mode-titlebar-{bg,color}-focused`, so the widget and the
native window stay the same colour.

The title-bar controls had no hover state. The shell's own hover
rules are weaker selectors than the extension's resting rule, so the
resting navy won the cascade even while hovered, leaving only an
opacity lift that is invisible against a saturated blue bar. Restate
hover, active and focus-visible at the extension's specificity.
Close reads `--wpd-btn-danger-hover`, the same token the reader
window's close control resolves through as a `<wpd-window-button
danger>`, so both title bars redden identically under a desktop
theme that retints it.

Adds PHPUnit coverage for all three registration surfaces, including
that the icon reaches the desktop-icons payload the Apps & Icons tab
actually reads.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015sKW1mu1SGg5k9oSHgxv5s
# Conflicts:
#	.github/workflows/ci.yml
#	.wordpress-org/blueprints/blueprint.json
#	README.md
#	bin/package-extensions.sh
@AllTerrainDeveloper
AllTerrainDeveloper merged commit 3106d97 into trunk Jul 31, 2026
5 checks passed
@AllTerrainDeveloper
AllTerrainDeveloper deleted the feat/sol-im-feed-reader branch July 31, 2026 11:28
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