Blank Home v1 — TST/BST/Dialog/Leader/MouseGuard + spec resurrection#52
Open
gmrdad82 wants to merge 287 commits into
Open
Blank Home v1 — TST/BST/Dialog/Leader/MouseGuard + spec resurrection#52gmrdad82 wants to merge 287 commits into
gmrdad82 wants to merge 287 commits into
Conversation
gmrdad82
added a commit
that referenced
this pull request
May 22, 2026
… + DateTime polish User feedback round after PR #52 opened. THEME (item 1) - Pito::Theme::Sections drift fixed — every section's bg now derives from canonical 4% recipe in tmp/dracula-swatches-v2.html (home was hand-picked #2c2a36 ≈ 1%, now #2e2e3e exact 4%) - settings #34333b preserved via USER_LOCKED_BG (historical override) - _theme.css regenerated via rake pito:theme:export; Pito::Theme delegates to Pito::Theme::Sections::BG (single source of truth) - spec/services/pito/theme/sections_spec.rb: 25 examples locking new recipe-derived values - docs/design.md: canonical recipe paragraph added next to Screen accents list (4% bg / 35% border / 18% focus tint) CABLE TEST INFRA (items 2 + 5) - app/services/pito/cable_broadcaster.rb: broadcast_status_bar(kind:, payload:) extended with kind kwarg (default 'data') — source-compatible - app/sidekiq/pito/test/{sleep,failing,scheduled}_job.rb: 3 dummy jobs (busy / retry / scheduled queue probes); docblocks document purpose - lib/tasks/pito_test_broadcast.rake: pito:test:broadcast_{sync,sidekiq,notifications} + enqueue_{sleep,failing,scheduled}_job - app/controllers/test_broadcast_controller.rb: POST /_test/broadcast (development+test only, env-gated) - config/routes.rb: gated mount - app/javascript/pito_actions.js: window.Pito.testBroadcast(kind, payload) for browser console - specs: cable_broadcaster_spec (broadcast envelope) + sleep/failing/scheduled job specs + request spec (env gate + envelope passthrough) — 25 examples DATETIME ← NOTIFICATIONS (change 1) - tui_status_bar_controller.js: third branch in kind switch — dispatchNotificationsChanged - tui_date_time_controller.js: onNotificationsChanged listener toggles .dt-has-future-notif - .sb-clock.dt-has-future-notif { color: var(--section-accent-home); } — Pito brand purple when future_count > 0 - spec regression for data-action wiring DATETIME MIDNIGHT SCRAMBLE REMOVED (later directive) - Stripped startScramble / stopScramble / scrambleDigits + SCRAMBLE_DURATION_MS / SCRAMBLE_FRAME_MS constants + lastDay tracking + tick() rollover branch - ~50 lines deleted; tick() now just updates text directly every 1Hz - @contract JSDoc + component docblock updated SPACE+A ABOUT BUG FIX (item 3) - Root cause: leader fires pito:leader:open_about but no Stimulus controller listens - Created tui_about_dialog_controller.js: listens for pito:leader:open_about + pito:action:open_about, calls dialog.showModal() - Refactored command palette: dispatches pito:action:open_about instead of direct showModal (both paths converge) - Same pattern applied to Help dialog (SPACE+?) — tui_help_dialog_controller.js rewritten with listeners - Same pattern applied to CommandPalette (SPACE+:) — connect/disconnect register pito:leader:open_command + pito:action:open_command listeners on document - All three leader entries now reach their dialogs via single canonical event path INSERT MODE i KEY (question 1) - Root cause: tui-cursor controller's prior mount was on .settings-panes which the C-NUKE rebuild removed - Added tui-cursor to body data-controller (global mount) - Moved i key handler above focusable-existence check in handleNormalKey() so it flips lozenge on empty screens with zero focusables - INSERT mode now works on blank home ABOUT I18N COMPLIANCE (later directive) - Only one hardcode found: 'v' version prefix in version_string helper - Added tui.about.version_prefix: 'v' to config/locales/tui/en.yml - AGPL-3.0 / contact email already through tui.about.{license_value,contact_value} - 6 new specs in about_dialog_component_spec.rb: Stimulus wiring + 3 i18n source-of-truth probes (stub I18n.t to assert no hardcode) + 2 template-source guards VERIFICATION - bin/test spec/components/tui/ spec/services/pito/ spec/sidekiq/pito/ spec/requests/test_broadcast_spec.rb: 305 examples, 0 failures - bin/rails zeitwerk:check: clean - bundle exec rubocop: 654 files, 0 offenses
…indicator uniform offset - pipe brackets follow the panel's focus state instead of being pinned to var(--color-border); idle pipes use the same 30% section-accent mix as the panel border, focused pipes swap to var(--section-accent) — old pin rule removed - nested-focus exception keeps the outer pane's pipes muted when an inner sub-panel is the focused element (matches the existing outer-border + outer-title color-drop) - .pito-stack-grid gains padding-top: 10px so the first row of sub-panel titles + [reindex] action chips clear the scroll-wrapper clip line (was rendering as "ilisearch" / "yage AI" at the character mid-line) - scroll indicators now position against .pito-pane instead of .tui-panel-fieldset — removes the per-grid-cell sub-pixel rounding drift that pushed stack's indicators 1-2px right of the security/notifications column; right offset re-tuned from -14px to -4px against the new positioning context (same visible column on all panels)
…e-evaluate - .pito-stack-grid padding-top 10px -> 8px (7px title outset + 1px safety) — Meilisearch + Voyage AI sub-panels sit closer to the stack panel's top border - tui_scroll_indicator: window.resize listener added as safety net so scroll indicators re-evaluate visibility when the user resizes the window (ResizeObserver alone misses some deferred-reflow cases)
- user verified padding-top: 0 in DevTools — titles render into the parent .pito-pane's own 6px top padding zone (overflow: visible) so the grid needs no extra padding to clear the title outset - Meilisearch + Voyage AI sub-panels sit flush against the stack panel's top border
- visibility toggle runs unconditionally; position math stays guarded by max > 0 - previously the entire handle block was inside `if (max > 0)` so the visible class never got removed when content shrank below the overflow threshold — handle stayed pinned after a resize that fit all content
- .pito-pane:has(.pito-sub-panel) padding-top 14px -> 0 (the actual rule the user meant when they said "stack panel padding-top: 0") - .pito-stack-grid padding-top kept at 8px (the title clearance lives INSIDE the scroll wrapper since the scroll owns its own coordinate system; outer .pito-pane's padding-top can't help) - net visual: stack panel title + Meilisearch/Voyage AI sub-panels sit ~8px apart instead of 22px; titles no longer clip - .tui-scroll-indicator transform: scaleX(0.7) — arrows + handle glyphs visually ~9px wide instead of ~13px (the 4px shrink the user asked for); transform is visual-only so right: -4px positioning is unchanged
…inear - tui_cursor_controller: 95 lines of spatial scoring + Ctrl-hjkl dispatch removed; TAB/Shift-TAB now cycles panels in DOM order with wrap-around - input/select TAB passthrough: focus on a form field falls through to the browser's native field cycling instead of jumping panels - dialog focus trap still wins via the existing shouldIgnore/focusedScope guards - help dialog + help locale: 4 Ctrl-hjkl entries dropped; cycle_forward / cycle_backward retained - applyFocus + emitFocusChange untouched so tui-breadcrumb and other downstream listeners keep working
- target width = IPv4 standard "123.123.123.123" (15 chars) - IPv4 always fits unchanged - IPv6 longer than 15 chars now trims with a TRAILING ellipsis, preferring a group-boundary cut so the head reads as a clean prefix instead of the previous middle-ellipsis "first_two:…:last_two" that showed both ends and ate column width on every row - result examples: 2a0d:3344:7a3e:9efe:0c1f:dce9:24f1 -> "2a0d:3344:7a3e…" (15 chars), 2a02:2f04:7a3e:9efe:0c1f -> "2a02:2f04:7a3e…"
…created columns
- .col-action padding-right 8px -> 14px so [ ] is not glued to the device label
- .sessions-table__cell-last-seen + .sessions-table__cell-created (and matching col headers) gain padding-left: 14px so the two right-aligned date columns don't read as one ("last secreated")
…distribution - new .tui-table__td.col-action / .tui-table__th.col-action rule in the TUI primitive layer: padding-right 14px so every table with a checkbox column (channels, videos, sessions, bulk_operations, deletions) reads identically - sessions table IP column constrained to its content width (width: 1%, white-space: nowrap) so the surplus from the new 15-char IPv6 cap no longer pads the IP column — it auto-distributes to the right-aligned date columns - last-seen + created cells padding-left bumped 14 -> 24px so the two right-aligned date columns read as two distinct columns instead of "~4d ago~6d ago" glued together
- `<table style="table-layout: fixed">` -> `.sessions-table { table-layout: fixed }` (no inline style)
- 6x `<col style="width: X%">` -> 6 per-column classes resolving to pixel widths in the CSS
- widths: action 40 / device 140 / browser 90 / ip auto / last-seen 100 / created 100
- IP is the only flex column; everything else is bounded content with predictable size so pixels are the right tool
- drops the previous ad-hoc width:1% + nowrap rule on the IP cell and the padding-left 24 on the date columns — both were workarounds for the percent-based widths
… row
- root cause: zebra rules at the global / stack / sessions / kv-table layers selected `tr:nth-child(even)` unconditionally. The focus rule `tr[data-tui-focusable-focused] > td { background: inherit }` (no !important) lost the specificity battle on even rows, and the sessions table's defensive `background-color: transparent !important` made it worse — even rows were ALWAYS transparent, focus or not
- fix: add `:not([data-tui-focusable-focused="yes"]):not([data-tui-cursor-row-focused="yes"])` to all four zebra selectors so the rule simply doesn't match a focused row. The focus tint then wins on cascade because no zebra rule competes
- the `!important` on the sessions opt-out is dropped — the `:not` exclusion makes it unnecessary
- covers: global table zebra, .tui-table--stack opt-out, .sessions-table opt-out (row + cell), .kv-table opt-out
- net: keyboard cursor visible on every row of the sessions table AND the kv-tables inside the stack panel sub-panels
- global `table:not(.detail-table) tr:nth-child(even) { --color-bg-alt }` rule removed
- per-table zebra opt-outs at .tui-table--stack, .sessions-table (row + cell), .kv-table all removed — useless now that there is no zebra to opt out of
- legacy FB-68 / F3-DEEP-B / 2026-05-23 sessions-zebra defensive blocks deleted with the rules they were narrating
- keyboard focus tint now has no zebra competition; rows of the sessions table + the kv-tables inside the stack sub-panels will show the cursor on every row
- action 30 / device 105 / browser 60 / ip auto / last-seen 80 / created 70 (eye-balled by user in DevTools, matched) - drop the .col-action padding-right: 14px override I added earlier — the default 8px right padding from .tui-table__td gives the `[ ]` glyph enough breathing room at the new 30px column width; canonical convention is documented as "30px in the colgroup, default cell padding"
- embeds table: collection / embedded rows (games + bundles), sortable - info table: model / last indexed / HNSW indexes / last 24h, NOT sortable - small top-margin between the two tables, no border - new i18n: settings.voyage.col_collection + col_embedded - voyage_sub_panel_component.rb docblock updated to reflect the split
- always adds tui-table__th + tui-table__th--right (numeric) or --left (default) - preserves existing sortable + num + extra_class composition - net: every table using SortableHeaderComponent (Meilisearch / Postgres / Assets / Voyage embeds sub-panels, channels, videos, bundle modal) now reads visually identical to the sessions table headers — same V4 underline (solid asc, dashed desc) applied via the shared `th.sortable.sort-asc/.sort-desc` rules
…erComponent shape - CSS: drop the generic `[data-tui-focusable-focused="yes"]` catchall from the focus-tint bg rule. The specific style rules (`:row`, `:action`, `:checkbox_label`) already paint the bg on the focusables that earned it. The catchall was painting bg on inert sub-panel-root focusables (Postgres sub-panel flooded with bg-tint when selected as a navigation stop) - sortable_keys_controller: support BOTH sortable header shapes * `<th class="sortable"><a>...</a></th>` (server-rendered via sort_link_to, sessions table) * `<th class="sortable">...</th>` (client-side via SortableHeaderComponent, stack sub-panels) - `s` / `S` now cycle + toggle direction on the stack sub-panel tables too - active sort detection reads either `a.sort-asc/desc` (anchor shape) or `th.sort-asc/desc` (bare shape)
…initial scramble) - application_helper#current_page: dashboard#index returns the first panel's i18n title (channels overview) so the server renders the breadcrumb with the SAME value the cursor controller will apply on connect - breadcrumb's first applyState now compares "channels overview" -> "channels overview" -> no diff -> no scramble - previous behavior: breadcrumb rendered "home" idle, then scrambled to "channels overview" once cursor's initial focus event fired — a visible double paint on every page load
…sables + voyage rename + browser col + home row-gap - V4 underline cascade: stack sub-panel selectors added to the asc/desc/color rules so the section-accent border-bottom + text color now win the specificity fight against the muted .tui-table--stack thead th override; sort indicator visible on Meilisearch/Postgres/Assets/Voyage embeds - sortable_keys_controller: s / S scope narrows to the focused sub-panel when one is selected (was sorting Voyage every time on stack-panel focus regardless of which sub-panel held the cursor) - 4 new inert header focusables (meilisearch_header, postgres_header, assets_header, voyage_header) wired into each sub-panel's focusables list so j/k can land the cursor on the table heading before pressing s/S - voyage rename: col_collection "collection" -> "embeds"; row labels drop "embedded" suffix (games_embedded "games embedded" -> "games"; bundles_embedded "bundles embedded" -> "bundles") - sessions table browser column 60px -> 70px so SmokeAgent / wave-a2-smoke browser labels stop bleeding into the IP column - home grid row-gap 12px -> 17px (+5px per user) for more relaxed vertical breathing between rows; column-gap stays 12px
…st lift - inert focusables on <tr> elements (stack sub-panel table headings) now paint the focus tint so the cursor is visible when it lands on them. Inert focusables on non-<tr> elements (sub-panel root <div>) stay paint-free so they don't flood the panel with bg-tint - focused-row muted text brightens 50% toward the full text token so it reads cleanly on the accent-tinted bg without losing its "muted" relative ordering. Covers .text-muted and .pito-sub-panel__hint.is-muted - accent text already pops against the bg-tint; default text needs no boost
- table.tui-table--stack last <th> / <td> in each row -> padding-right: 0 so the focused-row tint stops AT content instead of leaving an 8px whitespace gap past 17/17 / 22/22 / 519 KB
…-traversal panels - syncSubPanelFromFocusable: emit tui:panel-focus-changed after the sub-panel marker swaps so the breadcrumb picks up the new sub-panel title - previously the cursor moved into a new sub-panel's focusable via j/k, the data-tui-cursor-sub-panel-focused attribute updated, but no event fired — breadcrumb stayed pinned to the previous sub-panel - user was right: the breadcrumb was only reacting to panel-level focus changes (TAB / Ctrl+arrow / click) not the flat j/k traversal in stack-style panels
…n TST + per-target panels - delete Tui::PauseControlComponent + its Stimulus controller + spec (|| glyph approach was a misread of the brain dump) - Tui::SyncIndicatorComponent now drives BOTH the TST aggregate state AND per-target panel/sub-panel toggles via mode: :tst | :target - 4 canonical states: idle [ ] muted, active [x] accent no-shimmer, syncing [x] accent shimmer-on-sync-word-only, disconnected [!] red (danger) - localStorage key: pito.sync.<target> = "yes" enabled (default), "no" suppress; parent target inherits to children - cable suppression: tui_panel_cable_controller imports isTargetSyncDisabled from sync indicator controller; payload dropped client-side when target is "no" - 7 panel/sub-panel ERBs swap to Tui::SyncIndicatorComponent(mode: :target, target:, parent_target:, focusable_key:) - focusables rename: *_pause -> *_sync on Stack + 4 sub-panels + Notifications + Security - new i18n: tui.tst.sync.syncing + .disconnected; row 3 right column gap 12 -> 17px - specs: SyncIndicator spec 52 examples (2 modes x 4 states + edge cases); touched panel specs updated; 168 examples all green
…panel - panel/sub-panel VCs declare panel_commands array (5-7 entries each); serialized to data-panel-commands="<JSON>" via panel_root_data (panels) + Tui::SubPanelComponent (sub-panels) - new Pito::CommandPalette::Collector — Ruby twin walking panel + sub-panel + screen catalogs in sub-panel -> panel -> screen order; consumed by future Ratatui screen export - tui_command_palette_controller rebuilds catalog on each open() by scanning the focused panel + focused sub-panel data-panel-commands attrs; client-side action short-circuits added for :sort_table, :sync_toggle, :click_focusable, :focus_focusable - new ActionRegistry entries: sort_table, sync_toggle, click_focusable, focus_focusable, revoke_all_except_current (stub), revoke_selected_sessions (stub) - 25 new tui.commands.* i18n entries - specs: +27 examples across collector + 7 panels; 243 examples total all green - calendar / notifications-feed commands NOT wired (Phase 3 content lands first)
- new app/javascript/controllers/tui_url_hash_state_controller.js - API: setValue(v), getValue(), clearValue(); writes key=value entries into window.location.hash via history.replaceState; reads back on connect and dispatches tui:url-hash-state-restored on the element - multi-key hash format mirrors sortable_table_controller (k1=v1&k2=v2) - generalizes the pushState pattern so calendar mode toggle / filter chips / future state-bearing controllers consume it via a single mount instead of reinventing - sortable_table_controller left untouched (stable)
…tern) - new app/views/settings/_meilisearch_section.html.erb partial wrapped in <div id="meilisearch_section"> with turbo_stream_from "reindex_status" - meilisearch_sub_panel_component.html.erb renders the partial instead of an inline toggle - MeilisearchReindexJob#broadcast_meilisearch_section helper Turbo-replaces #meilisearch_section on completion (called from ensure alongside the voyage equivalent) - new i18n: settings.meilisearch.reindexing_html - no manual refresh needed after reindex completes; idle [reindex] returns automatically - 22 spec examples green
phase 5 (lib/tasks/pito_test_panel_seeds.rake + spec): - pito:test:notification[type,severity,title] -> pito:home:notifications_feed - pito:test:calendar_entry[type,offset_days] -> pito:home:calendar - pito:test:channel_milestone[channel,kind,value] -> notifications_feed + calendar (both fire) - pito:test:session_login[device,browser,ip] -> pito:home:security - pito:test:system_event[kind] (retry_queue/dead_queue/storage/log_files) -> notifications_feed - pito:test:clear_panel_seeds — purges marker-tagged seeds (Notification.dedup_key, CalendarEntry.source_ref, Session.user_agent prefixed with "pito:test:") - 22 spec examples green phase 6 (help dialog audit): - section_nav corrected from broken `g h/v/g` -> `Space h/v/g` (leader menu) - new groups added: focusable_nav (j/k/Enter) + sort (s/S) — were missing despite being wired in cursor + sortable_keys controllers - leader menu (h/v/g/?/:/q/a) verified correct + complete — no changes needed - 50 specs (28 help + 22 leader) all green
…es" rename - stale expectation from before commit 00ae723 (i18n key kept, label changed)
…der Space-s - focus tint variant D applied (color-mix accent 12% solid over dracula-bg) — user pick from tmp/cursor-and-month-v1.html - sync VC idle color now accent (was muted) — per new "all actions accent" rule captured in CLAUDE.md + docs/design.md - sync VC left padding: 0 4px -> 0 (the title-actions slot's gap already gives breathing room) - 5 new panel sync VCs wired: channels (renamed from "channels overview"), latest videos, upcoming games, notifications feed, calendar — each focusables list now leads with <panel>_sync - calendar title-actions slot now renders "month [schedule]" (bracket-to-space rule); Tui::ViewToggleComponent gains active_style: :plain + :accent color - 5th sync state added: mixed (glyph [-], accent color, no shimmer) — for parent when sub-panels disagree - stack propagation: parent toggle bulk-writes to children; mixed-children re-aggregates parent to [-]; CHILDREN_BY_PARENT map registers home.stack - leader menu Space-s -> toggle TST sync; new pito_actions.js handler flips pito.sync.home master flag; isTargetSyncDisabled cascades master to every home.* target - SPACE in INSERT on action-button focusable now toggles the focusable (sync VC, etc.) via toggleFocusedFocusableCheckbox extension - docs/design.md + CLAUDE.md capture the actions-accent + bracket-to-space rules; per-fix specs updated (198 examples green for touched files)
…g-ellipsis semantics - MAX_LEN 15 -> 13 (cut 2 more characters per user pick); IPv4 unchanged for ≤13 chars, longer IPv4/IPv6 get trailing ellipsis at group/octet boundary - spec rewritten: 6 old middle-truncation expectations replaced with trailing-ellipsis assertions - examples: 255.255.255.255 -> "255.255.255.…", 2a0d:3344:7a3e:... -> "2a0d:3344…" (10 chars, group-boundary cut)
- ctrl+k search box: 16px (text-base), text-fg instead of muted - section items: always show /slash command on the right - ctrl+m (audio mute): only bind on /chat/:uuid pages via data-audio-chat-page - spec: update section_component_spec to match new two-span item layout - locales: rewrite start_screen tips, event thinking, auth, dispatch_failed (50 entries each) - README: "why this exists" section with 6 channel avatars (docs/avatars/) - avatars: re-exported preserving alpha channel transparency - schema.rb: solid_cable/cache/queue tables from pending migrations Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Re-export all 6 channel avatars with a hard circular clip so transparent corners render correctly on GitHub's white background instead of showing as white rectangles. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Reverse order: mini-status slides out right + filter slides down + scrollback fades (parallel) → chatbox shrinks symmetrically ← → → chatbox rises to center → navigate "/". Easing is the mirror of the forward animation (ease-out vs ease-in) and timing constants match. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rettier
Gems updated: puma 8.0.2 (CVE-2026-47736/47737), jbuilder 2.15.1,
bootsnap 1.24.5, view_component 4.11, jwt 3.2.0, faraday 2.14.2,
rqrcode 3.2.0, neighbor 1.1.1 (Gemfile constraints bumped for the
latter two). GitHub Actions: actions/checkout v4 → v6.
README: replace <table> avatar row with standard <p> contributor-row
pattern — avoids GitHub's .markdown-body table img { background-color }
rule that was filling transparent PNG corners with black. Prettier pass
on README, AGENTS.md, and docs/plan-beta-reboot-04-consolidation.md.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Removes handle labels and collapses all 6 avatar links onto one unbroken line so GitHub renders them as a proper horizontal row. prettier-ignore keeps CI from reformatting it back. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
README: fix section headings to title/sentence case (Stack, Getting started, Docs, Sounds, License). EXTRA.md: rewrite to reflect current state — chat-first interface, active specs, SolidQueue, no plan references. architecture.md: replace stale Plan 1/2+ content with current routes, component tree, and dispatch pipeline. AGENTS.md: remove Plan 2/3 references from pito-specific sections. brakeman.ignore: suppress three false positives (SQL injection on app-controlled symbol column, HTTP verb confusion on intended-URL stash, allow_other_host on Google OAuth redirect). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Strip audio hint (ctrl+m / mute) from MiniStatusComponent :start mode — it only renders in :connection mode (chat pages). - Audio controller now waits for pito:chat-page-ready before binding the ctrl+m keydown, so it activates after the JS home→chat transition too. - home_transition_controller dispatches pito:chat-page-ready and sets data-audio-chat-page on <body> after morphToConversation. - Update mini_status_component_spec to match new :start behaviour. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
KIND_VALUES/SEVERITY_VALUES referenced Notification model at class load time; Zeitwerk eager load raised NameError (model not yet implemented), cascading as FrozenError across every spec. Stub with [].freeze until the model lands. Also drop PARALLEL_TEST_PROCESSORS from 8 → 4. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
File was named simple_sidekiq_job.rb after the Solid Queue migration renamed the class to SimpleJob; Zeitwerk expected SimpleSidekiqJob and blew up on eager load, cascading FrozenErrors across all specs. Split into two files matching their constant names. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The gem was removed during the unused-gems sweep but is still required at file top level in analytics_client.rb, client.rb, and service_factory.rb, causing a LoadError during Zeitwerk eager load and cascading all specs. AnalyticsClient is actively used by 4 jobs. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
YoutubeApiCall model was dropped in the schema baseline; the class-body
constant AUDIT_KIND = YoutubeApiCall::KIND_ANALYTICS_V2 blew up Zeitwerk
eager load. Replaced with the original value ("analytics_v2").
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
app/assets/builds/ is gitignored; tailwind.css is absent in CI, causing stylesheet_link_tag to raise in every request spec that renders a full layout. Add a tailwindcss:build step before the parallel DB setup. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Echo segments now carry `authenticated:` in their payload (default true for backward compat). Unauthenticated echoes (before /login succeeds, the /login command itself) omit the `· @all` channel pill; authenticated ones keep it. /logout always shows it. /connect now emits the echo first in all code paths so the Turbo Stream turn container exists before the error event appends into it (fixes the silent-drop / must-refresh bug). The not_configured error payload now includes a `credentials` hash; ErrorComponent renders a ctrl+o-expandable table showing ✓/✗ per key (client_id, client_secret, redirect_uri) with green/red colouring. Chatbox filter labels lowercased: "Channel" → "channel", "Period" → "period". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace the ctrl+o-expandable credential section with an always-visible kv-table. Each of the four keys (Client ID, Client Secret, Redirect URI, API Key) shows green [set] / actual URI or red MISSING. The expand/ctrl+o mechanism is preserved only for the plain-detail error path. i18n trimmed to just the header sentence. Plan doc: T28.0.a–d logged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Lexer: read_word now detects "://" and consumes the entire URL (up to next whitespace) as one word token. This fixes redirect_uri=http:// localhost:3027/... being split on "localhost:3027" → spurious kwarg. Handler base class: adds help?/show_help so any handler can expose --help with one line at the top of call. Default show_help is a no-op fallback; subclasses override with real content. Config: return show_help if help? at top of call; show_help picks general or per-provider content based on first known-provider arg. i18n: full help strings for /config --help and /config <provider> --help for all four providers. Plan doc: T28.0.e added, bogus ## P28.0 removed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
docker-compose.yml: named volumes postgres_data + rails_storage; web service (production) using existing Dockerfile; postgres now persists across docker compose down. Dockerfile.dev + docker-compose.dev.yml: development overlay with a bind-mount for live code editing; no image rebuild needed per save. bin/boot: bin/boot (production) / bin/boot --dev (development). Requires Docker Compose v2. RAILS_MASTER_KEY must be set for production. bin/docker-entrypoint: db:prepare on both server and bin/dev boot; seeds automatically in development mode. Migrations squashed: 3 prior files replaced by single 20260602120000_squash_baseline.rb (guarded with table_exists? so existing DBs skip safely). CI updated to db:setup. Local DB and storage purged per user request. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Supersedes old T28.2 (confirmation_prompt) and T28.3 (wire /confirm). New flow: #greek-NNNN handle above segment; user types #handle confirm/cancel; no echo emitted; original segment replaced in-place via Turbo Stream. Also adds T28.0.f for Docker work already shipped. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
/demo (dev only): visual inventory of all segment kinds — echo (auth/unauth), assistant_text (plain/subsequent), error (plain/detail/ credential table), thinking (spinning/resolved), confirmation_prompt (pending/processing/cancelled/confirmed), logout. ConfirmationPromptComponent redesigned: - orange accent retained - body: replaces prompt_key: as primary text (falls back for legacy) - meta line: timestamp · #handle · @ALL (handle + auth-aware @ALL) - processing state: Braille spinner + confirmation-vocabulary verb - resolved state: original body + hairline + outcome_text appended New confirmation verb dictionary (pito.event.thinking.confirmation). EventRenderer passes event: to confirmation_prompt for timestamp. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s in ERB) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
pito--logout Stimulus controller fires Turbo.visit('/') on connect —
demo now renders the purple segment directly without the controller wrapper.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…elevated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this is
A ground-up rebuild of pito — from the old Rust TUI + fragmented Rails surfaces into a
single, coherent chat-first Rails app for managing multiple YouTube channels.
What landed
Foundation
pito:test:*/pito:tools:*Chat core (S-series + C-series)
/connect+ Google OAuth multi-channel picker;/disconnect;/login;/logout;/help;/new;/resumeUI
/) — centered chatbox, ASCII logo, rotating tips, corner chrome/chat/:uuidtransition: choreographed fade/drop/expand animationOpen-source prep
What's next
The remaining scope (video import, game search, multi-conversation sidebar, VideoPreview edit/publish) is still being planned and will be finalised before execution on this branch.
Test plan
bundle exec rspec— 673 examples, 0 failures/renders start screen; Enter on non-empty input transitions to/chat/:uuid/logoutreverse-animates (mini-status slides right, chatbox shrinks then rises) then navigates to//chat/*/connect→ Google OAuth consent → channels imported;/disconnect @handleremoves one