Commit Graph

41 Commits

Author SHA1 Message Date
5a43621114 Add mouse wheel and keyboard scrolling support to REPL
- Add scroll_offset to REPLState (max 50 lines)
- Modify _render_repl() to use manual scroll position
- Add scroll_output(delta) method for scroll control
- Add PageUp/PageDown keyboard support (scroll 10 lines)
- Add mouse wheel support via SGR mouse tracking
- Update HUD to show scroll percentage (like vim) and position
- Reset scroll when new output arrives
- Add tests for scroll functionality
2026-03-30 19:16:07 -07:00
7d9a0815a3 Add 'available' command to list all effect types
- Add _cmd_available() method to list all registered effect types
- Discover plugins and query registry to get complete list
- Add 'available' to help text and command processing
- Update help description for 'effects' command to clarify it shows current pipeline
2026-03-30 19:16:07 -07:00
6c56f0a398 Add pipeline mutation commands to REPL
- Add help text for add_stage, remove_stage, swap_stages, move_stage commands
- Implement _cmd_add_stage, _cmd_remove_stage, _cmd_swap_stages, _cmd_move_stage methods
- Update _handle_pipeline_mutation in main.py and pipeline_runner.py
- Fix fragile test by testing output buffer directly instead of rendered output
2026-03-30 19:16:07 -07:00
ac788fdc6d Add Ctrl+C quit handling to REPL
- Add _quit_requested flag to TerminalDisplay
- Add request_quit() method to TerminalDisplay
- Handle 'ctrl_c' key in REPL input loops in both pipeline_runner.py and main.py
- When Ctrl+C is pressed, request_quit() is called which sets the flag
- The main loop checks is_quit_requested() and raises KeyboardInterrupt
2026-03-30 19:16:07 -07:00
43df1fe088 Fix REPL HUD layout by removing cursor positioning codes
- Remove \033[1;1H, \033[2;1H, \033[3;1H from HUD rendering
- HUD text now appears at correct positions without cursor interference
- Prompt appears at left margin as expected
2026-03-30 19:16:07 -07:00
61dc1410e8 Add REPL usage documentation and fix raw mode handling
- Fix raw mode enabling to not duplicate with UI border mode
- Add REPL_USAGE.md with comprehensive guide
- Add examples/repl_demo_terminal.py example script
2026-03-30 19:16:07 -07:00
f029f30fad Add REPL support to run_pipeline_mode_direct()
- Detect REPL effect in pipeline and enable interactive mode
- Enable raw terminal mode for REPL input capture
- Add keyboard input loop for REPL commands
- Add _handle_pipeline_mutation() function for pipeline control
2026-03-30 19:16:07 -07:00
f8a3093155 Add REPL effect detection and input handling to pipeline runner
- Detect REPL effect in pipeline and enable interactive mode
- Enable raw terminal mode for REPL input capture
- Add keyboard input loop for REPL commands (return, up/down arrows, backspace)
- Process commands and handle pipeline mutations from REPL
- Fix lint issues in graph and REPL modules (type annotations, imports)
2026-03-30 19:16:07 -07:00
b4f22b9f48 feat(repl): Add REPL effect with HUD-style interactive interface
Implement a Read-Eval-Print Loop (REPL) effect that provides a
HUD-style overlay for interactive pipeline control.

## New Files

- engine/effects/plugins/repl.py - REPL effect plugin with command processor
- engine/display/backends/terminal.py - Added raw mode and input handling
- examples/repl_simple.py - Simple demonstration script
- tests/test_repl_effect.py - 18 comprehensive tests

## Features

### REPL Interface
- HUD-style overlay showing FPS, command history, output buffer size
- Command history navigation (Up/Down arrows)
- Command execution (Enter)
- Character input and backspace support
- Output buffer with scrolling

### Commands
- help - Show available commands
- status - Show pipeline status and metrics
- effects - List all effects in pipeline
- effect <name> <on|off> - Toggle effect
- param <effect> <param> <value> - Set parameter
- pipeline - Show current pipeline order
- clear - Clear output buffer
- quit - Show exit message

### Terminal Input Support
- Added set_raw_mode() to TerminalDisplay for capturing keystrokes
- Added get_input_keys() to read keyboard input
- Proper terminal state restoration on cleanup

## Usage

Add 'repl' to effects in your configuration:

## Testing

All 18 REPL tests pass, covering:
- Effect registration
- Command processing
- Navigation (history, editing)
- Configuration
- Rendering

## Integration

The REPL effect integrates with the existing pipeline system:
- Uses EffectPlugin interface
- Supports partial updates
- Reads metrics from EffectContext
- Can be controlled via keyboard when terminal display is in raw mode

Next steps:
- Integrate REPL input handling into pipeline_runner.py
- Add keyboard event processing loop
- Create full demo with interactive features
2026-03-30 19:16:07 -07:00
1f43cec8e5 feat(hybrid): Add hybrid preset-graph configuration system
Implement Option 5: Hybrid preset-graph system that combines preset
simplicity with graph flexibility, providing 70% reduction in config
file size compared to verbose node DSL.

## New Files

- engine/pipeline/hybrid_config.py - Core hybrid config parser
- examples/hybrid_config.toml - Example hybrid configuration (20 lines)
- examples/hybrid_visualization.py - Demo script using hybrid config
- tests/test_hybrid_config.py - Comprehensive test suite (17 tests)
- docs/hybrid-config.md - Complete documentation

## Key Features

1. **Concise Syntax** (70% smaller than verbose DSL):

2. **Automatic Connections**: Linear pipeline order is inferred

3. **Flexible Configuration**:
   - Inline objects:
   - Array notation:
   - Shorthand:

4. **Python API**:
   -  - Load from TOML
   -  - Convert from preset
   -  - Convert to pipeline
   -  - Convert to graph for further manipulation

## Usage

Loading hybrid configuration...
======================================================================
✓ Hybrid config loaded from hybrid_config.toml
  Source: headlines
  Camera: scroll
  Effects: 4
    - noise: intensity=0.3
    - fade: intensity=0.5
    - glitch: intensity=0.2
    - firehose: intensity=0.4
  Display: terminal
  Auto-injected stages for missing capabilities: ['camera_update', 'render']
✓ Pipeline created with 9 stages
  Stages: ['source', 'camera', 'noise', 'fade', 'glitch', 'firehose', 'display', 'camera_update', 'render']
[?25l✓ Pipeline initialized
Executing pipeline...
  > MIT Tech Review .............................. LINKED [10]
  > Quanta .............................. LINKED [5]
  > Phys.org .............................. LINKED [30]
  > Ars Technica .............................. LINKED [20]
  > Science Daily .............................. LINKED [60]
  > Nature .............................. LINKED [75]
  > New Scientist .............................. LINKED [99]
  > NASA .............................. LINKED [10]
  > BBC Business .............................. LINKED [54]
  > BBC Science .............................. LINKED [36]
  > MarketWatch .............................. LINKED [10]
  > NPR .............................. LINKED [10]
  > Economist .............................. LINKED [299]
  > Al Jazeera .............................. LINKED [25]
  > France24 .............................. LINKED [24]
  > Guardian World .............................. LINKED [45]
  > BBC World .............................. LINKED [28]
  > ABC Australia .............................. LINKED [23]
  > DW .............................. LINKED [124]
  > Smithsonian .............................. LINKED [10]
  > Aeon .............................. LINKED [20]
  > Wired .............................. LINKED [48]
  > The Hindu .............................. LINKED [60]
  > Japan Times .............................. LINKED [29]
  > Nautilus .............................. LINKED [10]
  > Guardian Culture .............................. LINKED [24]
  > Literary Hub .............................. LINKED [10]
  > The Conversation .............................. LINKED [48]
  > The Marginalian .............................. LINKED [20]
  > Longreads .............................. LINKED [25]
  > Der Spiegel .............................. LINKED [19]
  > Atlas Obscura .............................. LINKED [27]
  > SCMP ..............................The Download: OpenAI is building a fully automated researcher, and a psychedelic
 pe                e  r          o      in                     e  a
    -      n    b  an          t        l       r                i l
       nl ad     n    co  ut n      h  l h  a    h  t e  o  d d     t r   c e
C n  ua t m co    e s             a  h  a e p      s          o  f nd
     h  w r    o  n    ec  le  o e   cl  r  a  e
T e D w  o     h   en a o ’s new A     ns, and n x -  n  u   a  r  c   s
W  t do ne  nucl ar r   tors  ea  f   w s  ?
 h  Penta o   s  l nni g  or  I co p nies  o tr in    cl s   i d   t   def nse o
T    ownl  d   pe  I s  S mi  t    dea , an    ok’  CS M   ws it
T   J  lies T a   vol  d       er nt   y    K     i e
Qu nt m   y  o  ap   Pi  ee     n   r  g    rd
T e  a h T a  E p  i     y B     urve  Are  ver   er
Why     u a   d        Stil   t u  le W t  t      ll S uff?
W e e  ome  ee S     s, She S es   S ace T  e M  e o  F ac  l
      ウ┋          ウ ホ          ウ ┆            メ   キ          ケ ┃            
Ligh -  s d     n  u      t s ar  f cia  str    r     a    mi   h  s   f    ng o
New resea  h exp  r s  h   a ad   of  i ms' u  q e t chnol g  s
L mi e  j    bl  k  oc     ob      o por  nit  s f   y  ng pe     in  oas  l  n
Are hu a    a ural   vi l nt?  ew re  arc  c  ll       o  - e   a s     ons
 a     m l      e e r  q a  s?
New      cove e  p o  s   ow  stro      eil   m t     a ter t   Ge in  8 e e
 o          a t                 g   3     a    g ye    b        r             b
How DICER cuts microRNAs with single-nucleotide precision                        LINKED [50]
======================================================================
Visualization Output:
======================================================================
The Download: OpenAI is building a fully automated researcher, and a psychedelic
 pe                e  r          o      in                     e  a
    -      n    b  an          t        l       r                i l
       nl ad     n    co  ut n      h  l h  a    h  t e  o  d d     t r   c e
C n  ua t m co    e s             a  h  a e p      s          o  f nd
     h  w r    o  n    ec  le  o e   cl  r  a  e
T e D w  o     h   en a o ’s new A     ns, and n x -  n  u   a  r  c   s
W  t do ne  nucl ar r   tors  ea  f   w s  ?
 h  Penta o   s  l nni g  or  I co p nies  o tr in    cl s   i d   t   def nse o
T    ownl  d   pe  I s  S mi  t    dea , an    ok’  CS M   ws it
T   J  lies T a   vol  d       er nt   y    K     i e
Qu nt m   y  o  ap   Pi  ee     n   r  g    rd
T e  a h T a  E p  i     y B     urve  Are  ver   er
Why     u a   d        Stil   t u  le W t  t      ll S uff?
W e e  ome  ee S     s, She S es   S ace T  e M  e o  F ac  l
      ウ┋          ウ ホ          ウ ┆            メ   キ          ケ ┃            
Ligh -  s d     n  u      t s ar  f cia  str    r     a    mi   h  s   f    ng o
New resea  h exp  r s  h   a ad   of  i ms' u  q e t chnol g  s
L mi e  j    bl  k  oc     ob      o por  nit  s f   y  ng pe     in  oas  l  n
Are hu a    a ural   vi l nt?  ew re  arc  c  ll       o  - e   a s     ons
 a     m l      e e r  q a  s?
New      cove e  p o  s   ow  stro      eil   m t     a ter t   Ge in  8 e e
 o          a t                 g   3     a    g ye    b        r             b
How DICER cuts microRNAs with single-nucleotide precision
======================================================================
✓ Successfully rendered 24 lines

## Comparison

| Format | Lines | Use Case |
|--------|-------|----------|
| Preset | 10 | Simple configs |
| **Hybrid** | **20** | **Most use cases (recommended)** |
| Verbose DSL | 39 | Complex DAGs |

All existing functionality preserved - verbose node DSL still works.
2026-03-30 19:16:07 -07:00
54f341a043 fix: Bug fixes and improvements
- fix(demo-lfo-effects): Fix math.sin() usage (was angle.__sin__())
- feat(pipeline): Add set_effect_intensity() method for runtime effect control
  - Allows changing effect intensity during pipeline execution
  - Returns False if effect not found or intensity out of range
  - Used by LFO modulation demo

The demo-lfo-effects.py script now works correctly with proper
math.sin() usage and the new set_effect_intensity() method provides
a clean API for runtime effect intensity control.
2026-03-30 19:16:07 -07:00
4c523c31e5 feat(graph): Integrate graph system with pipeline runner
Add support for loading pipelines from TOML graph configs in the
pipeline runner, maintaining full backward compatibility with presets.

- Add graph_config parameter to run_pipeline_mode() function
- Support both preset mode and graph mode with conditional logic
- Graph mode: loads from TOML file, uses graph-defined stages
- Preset mode: maintains existing behavior with manual stage building
- Handle items/context appropriately for each mode (graph uses own data sources)
- CLI display flag works in both modes

Backward compatible: graph_config defaults to None, so existing calls
to run_pipeline_mode(preset_name) continue to work unchanged.
2026-03-30 19:16:07 -07:00
3fd09b4c59 feat(graph): Add TOML-based graph configuration loader
Allow pipelines to be defined in TOML format with intuitive
node-and-connection syntax that's easy to read and edit.

- Add graph_toml.py with TOML parsing using tomllib
- Support simple format: "source": "headlines"
- Support full format: {"type": "camera", "mode": "scroll"}
- Parse connection strings in "A -> B -> C" chain format
- Add example pipeline_graph.toml demonstrating usage

Example TOML:
[nodes.source]
type = "source"
source = "headlines"

[nodes.camera]
type = "camera"
mode = "scroll"

[connections]
list = ["source -> camera -> display"]
2026-03-30 19:16:07 -07:00
68d7d9c420 feat(graph): Add adapter to convert graphs to pipelines
Bridge the new graph abstraction with existing Stage-based pipeline
system for backward compatibility.

- Add GraphAdapter class to map nodes to Stage implementations
- Handle effect intensity configuration (sets global effect state)
- Map camera modes to Camera factory methods (feed, scroll, horizontal, etc.)
- Auto-inject required dependencies (render, camera_update) via pipeline capabilities
- Support for all major node types: source, camera, effect, position, display

The adapter ensures that graphs seamlessly integrate with the existing
pipeline architecture while providing a cleaner abstraction layer.
2026-03-30 19:16:07 -07:00
e9219b7ded feat(graph): Add core graph abstraction for pipeline configuration
Introduce Node, Connection, and Graph classes for defining pipelines
as graphs instead of verbose XYZStage naming convention.

- Add NodeType enum (SOURCE, CAMERA, EFFECT, DISPLAY, etc.)
- Add Node, Connection, and Graph dataclasses with type hints
- Add validation for cycles and disconnected nodes using DFS
- Add factory methods: node(), connect(), chain() for easy graph building
- Support for both imperative and declarative graph construction

This provides the foundation for the graph-based DSL that replaces
the verbose XYZStage naming convention with intuitive node-and-connection syntax.
2026-03-30 19:16:07 -07:00
2d28e92594 feature/capability-based-deps (#53)
Reviewed-on: #53
Co-authored-by: David Gwilliam <dhgwilliam@gmail.com>
Co-committed-by: David Gwilliam <dhgwilliam@gmail.com>
2026-03-31 01:55:21 +00:00
b1f2b9d2be feat(daemon): add display abstraction and daemon mode with C&C 2026-03-15 19:20:47 -07:00
d5a3edba97 feat(effects): add plugin architecture with performance monitoring 2026-03-15 19:20:47 -07:00
15de46722a refactor: phase 4 - event-driven architecture foundation
- Add EventBus class with pub/sub messaging (thread-safe)
- Add emitter Protocol classes (EventEmitter, Startable, Stoppable)
- Add event emission to NtfyPoller (NtfyMessageEvent)
- Add event emission to MicMonitor (MicLevelEvent)
- Update StreamController to publish stream start/end events
- Add comprehensive tests for eventbus and emitters modules
2026-03-15 19:15:08 -07:00
35e5c8d38b refactor: phase 3 - API efficiency improvements
Add typed dataclasses for tuple returns:
- types.py: HeadlineItem, FetchResult, Block dataclasses with legacy tuple converters
- fetch.py: Add type hints and HeadlineTuple type alias

Add pyright for static type checking:
- Add pyright to dependencies
- Verify type coverage with pyright (0 errors in core modules)

This enables:
- Named types instead of raw tuples (better IDE support, self-documenting)
- Type-safe APIs across modules
- Backward compatibility via to_tuple/from_tuple methods

Note: Lazy imports skipped for render.py - startup impact is minimal.
2026-03-15 19:13:32 -07:00
cdc8094de2 refactor: phase 2 - modularization of scroll engine
Split monolithic scroll.py into focused modules:
- viewport.py: terminal size (tw/th), ANSI positioning helpers
- frame.py: FrameTimer class, scroll step calculation
- layers.py: message overlay, ticker zone, firehose rendering
- scroll.py: simplified orchestrator, imports from new modules

Add stream controller and event types for future event-driven architecture:
- controller.py: StreamController for source initialization and stream lifecycle
- events.py: EventType enum and event dataclasses (HeadlineEvent, FrameTickEvent, etc.)

Added tests for new modules:
- test_viewport.py: 8 tests for viewport utilities
- test_frame.py: 10 tests for frame timing
- test_layers.py: 13 tests for layer compositing
- test_events.py: 11 tests for event types
- test_controller.py: 6 tests for stream controller

This enables:
- Testable chunks with clear responsibilities
- Reusable viewport utilities across modules
- Better separation of concerns in render pipeline
- Foundation for future event-driven architecture

Also includes Phase 1 documentation updates in code comments.
2026-03-15 19:13:32 -07:00
f170143939 refactor: phase 1 - testability improvements
- Add Config dataclass with get_config()/set_config() for injection
- Add Config.from_args() for CLI argument parsing (testable)
- Add platform font path detection (Darwin/Linux)
- Bound translate cache with @lru_cache(maxsize=500)
- Add fixtures for external dependencies (network, feeds, config)
- Add 15 tests for Config class, from_args, and platform detection

This enables testability by:
- Allowing config injection instead of global mutable state
- Supporting custom argv in from_args() for testing
- Providing reusable fixtures for mocking network/filesystem
- Preventing unbounded memory growth in translation cache

Fixes: _arg_value/_arg_int not accepting custom argv
2026-03-15 19:13:32 -07:00
9ae4dc2b07 fix: update ntfy tests for SSE API (reconnect_delay) 2026-03-15 15:16:37 -07:00
757c854584 fix: apply ruff auto-fixes and add hk git hooks
- Fix pre-existing lint errors in engine/ modules using ruff --unsafe-fixes
- Add hk.pkl with pre-commit and pre-push hooks using ruff builtin
- Configure hooks to use 'uv run' prefix for tool execution
- Update mise.toml to include hk and pkl tools
- All 73 tests pass

fix: apply ruff auto-fixes and add hk git hooks

- Fix pre-existing lint errors in engine/ modules using ruff --unsafe-fixes
- Add hk.pkl with pre-commit and pre-push hooks using ruff builtin
- Configure hooks to use 'uv run' prefix for tool execution
- Update mise.toml to include hk and pkl tools
- Use 'hk install --mise' for proper mise integration
- All 73 tests pass
2026-03-15 15:16:37 -07:00
4844a64203 style: apply ruff auto-fixes across codebase
- Fix import sorting (isort) across all engine modules
- Fix SIM105 try-except-pass patterns (contextlib.suppress)
- Fix nested with statements in tests
- Fix unused loop variables

Run 'uv run pytest' to verify tests still pass.
2026-03-15 15:16:37 -07:00
6e39a2dad2 feat: migrate Ntfy message retrieval from polling to SSE streaming, replacing poll_interval with reconnect_delay for continuous updates. 2026-03-15 13:44:26 -07:00
11226872a1 feat: Implement interactive font selection by scanning the fonts/ directory for .otf, .ttf, and .ttc files, adding new fonts and updating documentation. 2026-03-15 03:52:10 -07:00
e6826c884c feat: Implement an interactive font face picker at startup, allowing selection of specific font faces from a font file. 2026-03-15 03:38:14 -07:00
9140bfd32b feat: Introduce a complementary color gradient for queue messages. 2026-03-15 02:44:38 -07:00
66c13b5829 refactor: Change firehose from a drifting overlay to a fixed bottom strip and message display from a top-pinned section to a centered overlay. 2026-03-15 02:26:44 -07:00
086214f05e style: remove firehose opaque row backdrop and background color 2026-03-15 01:31:44 -07:00
0f762475b5 feat: Apply a distinct background color to firehose lines. 2026-03-15 01:08:17 -07:00
b00b612da0 refactor: rename rendering components and variables for clarity, distinguishing between message, ticker, and scroll motion layers. 2026-03-15 00:58:36 -07:00
39dab4b22b feat: Implement a drifting firehose overlay that scrolls independently over the main ticker content. 2026-03-15 00:49:58 -07:00
9bd8115c55 feat: introduce the scroll engine with a main rendering loop for headlines, messages, and visual effects. 2026-03-14 23:36:56 -07:00
2c777729f5 feat: Introduce ntfy.sh message polling, content fetching with caching, and microphone input monitoring. 2026-03-14 23:34:23 -07:00
2e6b2c48bd feat: Introduce visual effects module, enhance text rendering with SSAA, and add shifting gradient support. 2026-03-14 22:15:48 -07:00
f6ad89769f feat: Implement OTF to terminal half-block rendering pipeline including font loading, text rasterization, word-wrap, and gradient coloring. 2026-03-14 21:53:47 -07:00
d3c403848c feat: Introduce translate module for Google Translate integration and location-based language detection, and add a new filter module. 2026-03-14 21:00:24 -07:00
119ed193c0 feat: Add terminal module. 2026-03-14 20:57:53 -07:00
dcc3718012 refactor: Create engine package, extracting data sources to sources.py, and add refactoring documentation. 2026-03-14 20:56:24 -07:00