ratatui_ruby-tea 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,7 +13,7 @@ class VerifyReadmeUsage
13
13
 
14
14
  VIEW: ^(Model, RatatuiRuby::TUI) -> untyped
15
15
 
16
- UPDATE: ^(RatatuiRuby::Event, Model) -> (Model | [Model, RatatuiRuby::Tea::Cmd::Quit])
16
+ UPDATE: ^(RatatuiRuby::Event, Model) -> (Model | [Model, RatatuiRuby::Tea::Command::Exit])
17
17
 
18
18
  def run: () -> void
19
19
  end
@@ -20,7 +20,7 @@ class WidgetCmdExec
20
20
  # Msg can be Event or [:got_output, Hash]
21
21
  type msg = RatatuiRuby::Event | [Symbol, Hash[Symbol, untyped]]
22
22
 
23
- UPDATE: ^(msg, Model) -> (Model | [Model, RatatuiRuby::Tea::Cmd::execution?])
23
+ UPDATE: ^(msg, Model) -> (Model | [Model, RatatuiRuby::Tea::Command::execution?])
24
24
 
25
25
  def run: () -> void
26
26
  end
data/sig/open3.rbs ADDED
@@ -0,0 +1,17 @@
1
+ #--
2
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ # SPDX-License-Identifier: LGPL-3.0-or-later
4
+ #++
5
+
6
+ # Local shim for Open3 methods not in stdlib RBS.
7
+ # The stdlib open3/0/open3.rbs only defines capture2e.
8
+ # TODO: Remove when upstream RBS adds these methods.
9
+
10
+ module Open3
11
+ # Executes a command and returns stdout, stderr, and status.
12
+ def self.capture3: (*String, ?stdin_data: String, ?binmode: boolish) -> [String, String, Process::Status]
13
+
14
+ # Executes a command with pipes for stdin, stdout, stderr.
15
+ def self.popen3: (*String) { (IO stdin, IO stdout, IO stderr, Thread wait_thr) -> void } -> Process::Status
16
+ | (*String) -> [IO, IO, IO, Thread]
17
+ end
@@ -6,42 +6,158 @@
6
6
  module RatatuiRuby
7
7
  module Tea
8
8
  module Command
9
+ # Interface for user-defined custom commands.
10
+ # Any callable satisfying this interface can be dispatched.
11
+ interface _Command
12
+ # Brand predicate for update return disambiguation.
13
+ def tea_command?: () -> true
14
+
15
+ # Execute the command's side effect.
16
+ # Push result messages via the outlet.
17
+ def call: (Outlet out, CancellationToken token) -> void
18
+
19
+ # Grace period for cooperative cancellation (seconds).
20
+ # Runtime waits this long before force-killing the thread.
21
+ def tea_cancellation_grace_period: () -> Float
22
+ end
23
+
9
24
  # Sentinel value for application termination.
10
25
  class Exit < Data
11
26
  def self.new: () -> instance
12
27
  end
13
28
 
14
- # Command to run a shell command via Open3.
29
+ # Runs a shell command and routes its output back as messages.
15
30
  class System < Data
16
31
  attr_reader command: String
17
32
  attr_reader tag: Symbol | Class
18
33
  attr_reader stream: bool
19
34
 
35
+ # Command identification for runtime dispatch.
36
+ def tea_command?: () -> true
37
+
38
+ # Grace period for cleanup after cancellation.
39
+ def tea_cancellation_grace_period: () -> Float
40
+
20
41
  # Returns true if streaming mode is enabled.
21
42
  def stream?: () -> bool
22
43
 
44
+ # Executes the shell command and sends results via outlet.
45
+ def call: (Outlet out, CancellationToken token) -> void
46
+
23
47
  def self.new: (command: String, tag: (Symbol | Class), stream: bool) -> instance
24
48
  end
25
49
 
26
50
  # Command that wraps another command's result with a transformation.
27
51
  class Mapped < Data
28
52
  attr_reader inner_command: execution
29
- attr_reader mapper: ^(untyped) -> untyped
53
+ attr_reader mapper: ^(Array[untyped]) -> Array[untyped]
54
+
55
+ # Command identification for runtime dispatch.
56
+ def tea_command?: () -> true
57
+
58
+ # Grace period delegates to inner command.
59
+ def tea_cancellation_grace_period: () -> Float
60
+
61
+ # Executes the inner command and transforms the result.
62
+ def call: (Outlet out, CancellationToken token) -> void
30
63
 
31
- def self.new: (inner_command: execution, mapper: ^(untyped) -> untyped) -> instance
64
+ def self.new: (inner_command: execution, mapper: ^(Array[untyped]) -> Array[untyped]) -> instance
65
+ end
66
+
67
+ # Sentinel value for command cancellation.
68
+ class Cancel < Data
69
+ attr_reader handle: _Command
70
+
71
+ def self.new: (handle: _Command) -> instance
72
+ end
73
+
74
+ # Sentinel value for command errors.
75
+ class Error < Data
76
+ attr_reader command: _Command
77
+ attr_reader exception: Exception
78
+
79
+ def self.new: (command: _Command, exception: Exception) -> instance
32
80
  end
33
81
 
34
82
  # Union type for all valid commands
35
- type execution = Execute | Mapped
83
+ type execution = System | Mapped | _Command
36
84
 
37
85
  # Creates a quit command.
38
- def self.exit: () -> Quit
86
+ def self.exit: () -> Exit
39
87
 
40
88
  # Creates a shell execution command.
41
89
  def self.system: (String command, (Symbol | Class) tag, ?stream: bool) -> System
42
90
 
43
91
  # Creates a mapped command for Fractal Architecture composition.
44
- def self.map: (execution inner_command) { (untyped) -> untyped } -> Mapped
92
+ def self.map: (execution inner_command) { (Array[untyped]) -> Array[untyped] } -> Mapped
93
+
94
+ # Request cancellation of a running command.
95
+ def self.cancel: (_Command handle) -> Cancel
96
+
97
+ # Creates an error sentinel.
98
+ def self.error: (_Command command, Exception exception) -> Error
99
+
100
+ # Wraps a callable for unique identity per dispatch.
101
+ def self.custom: (^(Outlet, CancellationToken) -> void callable, ?grace_period: Float?) -> _Command
102
+ | (?grace_period: Float?) { (Outlet, CancellationToken) -> void } -> _Command
103
+
104
+ # Private wrapper for Command.custom.
105
+ class Wrapped < Data
106
+ include Custom
107
+
108
+ attr_reader callable: ^(Outlet, CancellationToken) -> void
109
+ attr_reader grace_period: Float?
110
+
111
+ def self.new: (callable: ^(Outlet, CancellationToken) -> void, grace_period: Float?) -> instance
112
+ def call: (Outlet out, CancellationToken token) -> void
113
+ end
114
+
115
+ # Cooperative cancellation mechanism for long-running commands.
116
+ class CancellationToken
117
+ # Number of times cancel! has been called.
118
+ attr_reader cancel_count: Integer
119
+
120
+ def self.new: () -> instance
121
+
122
+ # Signals cancellation. Thread-safe.
123
+ def cancel!: () -> void
124
+
125
+ # Checks if cancellation was requested. Thread-safe.
126
+ def cancelled?: () -> bool
127
+
128
+ # Null object for commands that ignore cancellation.
129
+ class NoneToken < Data
130
+ attr_reader cancelled?: bool
131
+
132
+ def self.new: (cancelled?: bool) -> instance
133
+
134
+ # Does nothing. Ignores cancellation requests.
135
+ def cancel!: () -> nil
136
+ end
137
+
138
+ # Singleton null token.
139
+ NONE: NoneToken
140
+ end
141
+
142
+ # Mixin for user-defined custom commands.
143
+ module Custom
144
+ # Brand predicate for command identification.
145
+ def tea_command?: () -> true
146
+
147
+ # Cleanup time after cancellation is requested. In seconds.
148
+ # Default: 0.1 seconds (100 milliseconds).
149
+ def tea_cancellation_grace_period: () -> Float
150
+ end
151
+
152
+ # Messaging gateway for custom commands.
153
+ class Outlet
154
+ @queue: Thread::Queue[Array[untyped]]
155
+
156
+ def initialize: (Thread::Queue[Array[untyped]] queue) -> void
157
+
158
+ # Sends a tagged message to the runtime.
159
+ def put: (Symbol tag, *untyped payload) -> void
160
+ end
45
161
  end
46
162
  end
47
163
  end
@@ -5,94 +5,150 @@
5
5
 
6
6
  module RatatuiRuby
7
7
  module Tea
8
- # Interface for child bag modules (required by route).
9
- interface _Bag[M]
10
- def self.UPDATE: ^(top, M) -> [M, Command::execution?]
11
- def self.INITIAL: M
12
- end
13
-
14
8
  # Declarative DSL for Fractal Architecture.
15
9
  module Router
16
10
  def self.included: (Class base) -> void
17
11
 
18
- # Guard callable: receives model, returns truthy/falsy.
19
- type guard[M] = ^(M model) -> boolish
12
+ # Duck type for Data-like models that support `with`.
13
+ interface _DataModel
14
+ def public_send: (Symbol, *Object) -> Object
15
+ def with: (**Object) -> self
16
+ end
17
+
18
+ # Interface for fractal child modules (bags).
19
+ # Routed modules must have an UPDATE constant that handles child messages.
20
+ # NOTE: We use Module here because RBS interfaces can't declare class methods.
20
21
 
21
- # Handler callable: returns a command or nil.
22
- type handler = ^() -> Command::execution?
22
+ # Configuration for key handlers.
23
+ class KeyHandlerConfig < Data
24
+ attr_reader handler: (^() -> Command::execution?)?
25
+ attr_reader action: Symbol?
26
+ attr_reader route: Symbol?
27
+ attr_reader guard: (^(_DataModel) -> bool)?
23
28
 
24
- # Click handler: receives x, y coordinates.
25
- type click_handler = ^(Integer x, Integer y) -> Command::execution?
29
+ def initialize: (?handler: (^() -> Command::execution?)?, ?action: Symbol?, ?route: Symbol?, ?guard: (^(_DataModel) -> bool)?) -> void
30
+ end
26
31
 
27
- # Key handler config stored in handlers hash.
28
- type key_config[M] = {
29
- handler: handler?,
30
- action: Symbol?,
31
- route: Symbol?,
32
- guard: guard[M]?
33
- }
32
+ # Configuration for scroll handlers (no coordinates).
33
+ class ScrollHandlerConfig < Data
34
+ attr_reader handler: (^() -> Command::execution?)?
35
+ attr_reader action: Symbol?
34
36
 
35
- # Mouse handler config.
36
- type mouse_config = {
37
- handler: handler | click_handler,
38
- action: Symbol?
39
- }
37
+ def initialize: (?handler: (^() -> Command::execution?)?, ?action: Symbol?) -> void
38
+ end
39
+
40
+ # Configuration for click handlers (x, y coordinates).
41
+ class ClickHandlerConfig < Data
42
+ attr_reader handler: (^(Integer, Integer) -> Command::execution?)?
43
+ attr_reader action: Symbol?
44
+
45
+ def initialize: (?handler: (^(Integer, Integer) -> Command::execution?)?, ?action: Symbol?) -> void
46
+ end
40
47
 
41
48
  # Class methods added when Router is included.
42
- module ClassMethods
43
- def route: [M] (Symbol | String prefix, to: _Bag[M]) -> void
49
+ module ClassMethods : Module
50
+ @routes: Hash[Symbol, Module]
51
+ @actions: Hash[Symbol, ^() -> Command::execution?]
52
+ @key_handlers: Hash[String, KeyHandlerConfig]
53
+ @scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
54
+ @click_handler: ClickHandlerConfig?
55
+
56
+ def route: (Symbol | String prefix, to: Module) -> void
44
57
  def routes: () -> Hash[Symbol, Module]
45
58
 
46
- def action: (Symbol | String name, handler) -> void
47
- def actions: () -> Hash[Symbol, handler]
59
+ def action: (Symbol | String name, ^() -> Command::execution? handler) -> void
60
+ def actions: () -> Hash[Symbol, ^() -> Command::execution?]
48
61
 
49
- def keymap: () { () -> void } -> void
50
- def key_handlers: [M] () -> Hash[String, key_config[M]]
62
+ def keymap: () { (KeymapBuilder) [self: KeymapBuilder] -> void } -> void
63
+ def key_handlers: () -> Hash[String, KeyHandlerConfig]
51
64
 
52
- def mousemap: () { () -> void } -> void
53
- def mouse_handlers: () -> Hash[Symbol, mouse_config]
65
+ def mousemap: () { (MousemapBuilder) [self: MousemapBuilder] -> void } -> void
66
+ def scroll_handlers: () -> Hash[Symbol, ScrollHandlerConfig]
67
+ def click_handler: () -> ClickHandlerConfig?
54
68
 
55
- # Generates an UPDATE lambda from routes, keymap, and mousemap.
56
- def from_router: [M, Msg] () -> ^(Msg message, M model) -> [M, Command::execution?]
69
+ # Returns UPDATE callable that handles routing.
70
+ # Uses is_a? checks for Event::Key and Event::Mouse type narrowing.
71
+ # Model must be Data-like with `with` and field accessors.
72
+ def from_router: () -> RouterUpdate
73
+ end
74
+
75
+ # UPDATE callable returned by from_router with proper typing.
76
+ # Implements #call to satisfy Proc-like interfaces.
77
+ class RouterUpdate
78
+ @routes: Hash[Symbol, Module]
79
+ @actions: Hash[Symbol, ^() -> Command::execution?]
80
+ @key_handlers: Hash[String, KeyHandlerConfig]
81
+ @scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
82
+ @click_handler: ClickHandlerConfig?
83
+
84
+ def initialize: (
85
+ routes: Hash[Symbol, Module],
86
+ actions: Hash[Symbol, ^() -> Command::execution?],
87
+ key_handlers: Hash[String, KeyHandlerConfig],
88
+ scroll_handlers: Hash[Symbol, ScrollHandlerConfig],
89
+ click_handler: ClickHandlerConfig?
90
+ ) -> void
91
+
92
+ # Process message and return [model, command] tuple.
93
+ def call: (
94
+ (RatatuiRuby::Event::Key | RatatuiRuby::Event::Mouse | Array[Object]) message,
95
+ _DataModel model
96
+ ) -> [_DataModel, Command::execution?]
57
97
  end
58
98
 
59
99
  # Builder for keymap DSL.
60
100
  class KeymapBuilder
61
- @handlers: Hash[String, key_config[top]]
101
+ @handlers: Hash[String, KeyHandlerConfig]
102
+ @guard_stack: Array[^(_DataModel) -> bool]
62
103
 
63
- attr_reader handlers: Hash[String, key_config[top]]
104
+ attr_reader handlers: Hash[String, KeyHandlerConfig]
64
105
 
65
106
  def initialize: () -> void
66
107
 
67
- # Registers a key handler with optional guards.
68
- def key: [M] (
108
+ def key: (
69
109
  String | Symbol key_name,
70
- handler | Symbol handler_or_action,
110
+ (^() -> Command::execution?) | Symbol handler_or_action,
71
111
  ?route: Symbol?,
72
- ?when: guard[M]?,
73
- ?if: guard[M]?,
74
- ?only: guard[M]?,
75
- ?guard: guard[M]?,
76
- ?unless: guard[M]?,
77
- ?except: guard[M]?,
78
- ?skip: guard[M]?
112
+ ?when: (^(_DataModel) -> bool)?,
113
+ ?if: (^(_DataModel) -> bool)?,
114
+ ?only: (^(_DataModel) -> bool)?,
115
+ ?guard: (^(_DataModel) -> bool)?,
116
+ ?unless: (^(_DataModel) -> bool)?,
117
+ ?except: (^(_DataModel) -> bool)?,
118
+ ?skip: (^(_DataModel) -> bool)?
79
119
  ) -> void
120
+
121
+ def only: (
122
+ ?when: (^(_DataModel) -> bool)?,
123
+ ?if: (^(_DataModel) -> bool)?,
124
+ ?only: (^(_DataModel) -> bool)?,
125
+ ?guard: (^(_DataModel) -> bool)?
126
+ ) { () -> void } -> void
127
+
128
+ def skip: (
129
+ ?when: (^(_DataModel) -> bool)?,
130
+ ?if: (^(_DataModel) -> bool)?,
131
+ ?skip: (^(_DataModel) -> bool)?,
132
+ ?guard: (^(_DataModel) -> bool)?
133
+ ) { () -> void } -> void
134
+
135
+ private
136
+
137
+ def with_guard: ((^(_DataModel) -> bool)?) { () -> void } -> void
80
138
  end
81
139
 
82
140
  # Builder for mousemap DSL.
83
141
  class MousemapBuilder
84
- @handlers: Hash[Symbol, mouse_config]
142
+ @scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
143
+ @click_handler: ClickHandlerConfig?
85
144
 
86
- attr_reader handlers: Hash[Symbol, mouse_config]
145
+ attr_reader scroll_handlers: Hash[Symbol, ScrollHandlerConfig]
146
+ attr_reader click_handler: ClickHandlerConfig?
87
147
 
88
148
  def initialize: () -> void
89
149
 
90
- def click: (click_handler | Symbol handler_or_action) -> void
91
- def scroll: (:up | :down direction, handler | Symbol handler_or_action) -> void
92
-
93
- private
94
-
95
- def register: (Symbol key, handler | click_handler | Symbol handler_or_action) -> void
150
+ def click: ((^(Integer, Integer) -> Command::execution?) | Symbol handler_or_action) -> void
151
+ def scroll: (:up | :down direction, (^() -> Command::execution?) | Symbol handler_or_action) -> void
96
152
  end
97
153
  end
98
154
  end
@@ -5,22 +5,40 @@
5
5
 
6
6
  module RatatuiRuby
7
7
  module Tea
8
+ # MVU runtime event loop.
8
9
  class Runtime
10
+ # Active command tracking entry.
11
+ type active_entry = { thread: Thread, token: Command::CancellationToken }
12
+
13
+ # Widget type accepted by view functions.
14
+ type renderable = RatatuiRuby::_CustomWidget | RatatuiRuby::widget
15
+
16
+ # Duck type for update result that can be normalized.
17
+ # Steep needs a union type (not interface) for is_a? narrowing.
18
+ type update_result = [Object, Command::execution?] | Command::execution | Object
19
+
20
+ # Duck type for values that can be queried for command-ness.
21
+ interface _MaybeCommand
22
+ def nil?: () -> bool
23
+ def class: () -> Class
24
+ def respond_to?: (Symbol, ?bool) -> bool
25
+ def tea_command?: () -> bool
26
+ end
27
+
9
28
  # Starts the MVU event loop.
10
- def self.run: [M, Msg] (
11
- model: M,
12
- view: ^(M model, RatatuiRuby::TUI tui) -> untyped,
13
- update: ^(Msg msg, M model) -> (M | [M, Cmd::execution?] | [M, Cmd::Quit] | [M, nil]),
14
- ?init: ^() -> Msg
15
- ) -> M
29
+ def self.run: [Model] (
30
+ model: Model,
31
+ view: ^(Model, RatatuiRuby::TUI) -> renderable,
32
+ update: ^(RatatuiRuby::Event, Model) -> update_result?,
33
+ ?init: (^() -> RatatuiRuby::Event)?
34
+ ) -> Model
16
35
 
17
36
  private
18
37
 
19
- def self.validate_view_result!: (untyped widget) -> void
20
- def self.normalize_update_result: [M] (untyped result, M previous_model) -> [M, untyped]
21
- def self.valid_cmd?: (untyped value) -> bool
22
- def self.validate_ractor_shareable!: (untyped object, String name) -> void
23
- def self.dispatch: (untyped cmd, Queue queue) -> void
38
+ def self.validate_view_result!: (renderable? widget) -> void
39
+ def self.normalize_update_result: [Model] (update_result? result, Model previous_model) -> [Model, Command::execution?]
40
+ def self.validate_ractor_shareable!: [T] (T object, String name) -> void
41
+ def self.dispatch: (Command::execution command, Queue[Array[Symbol | Hash[Symbol, String | Integer]]], ?Hash[Command::_Command, active_entry] active_commands) -> Thread?
24
42
  end
25
43
  end
26
44
  end
@@ -0,0 +1,18 @@
1
+ #--
2
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ # SPDX-License-Identifier: LGPL-3.0-or-later
4
+ #++
5
+
6
+ module RatatuiRuby
7
+ module Tea
8
+ # Convenient short aliases for Tea APIs.
9
+ module Shortcuts
10
+ # Short alias for Command.
11
+ module Cmd
12
+ def self.exit: () -> Command::Exit
13
+ def self.sh: (String command, Symbol | Class tag) -> Command::System
14
+ def self.map: (Command::execution inner_command) { (Array[untyped]) -> Array[untyped] } -> Command::Mapped
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,10 @@
1
+ #--
2
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
3
+ # SPDX-License-Identifier: LGPL-3.0-or-later
4
+ #++
5
+
6
+ module RatatuiRuby
7
+ module Tea
8
+ VERSION: String
9
+ end
10
+ end
@@ -4,13 +4,25 @@
4
4
  #++
5
5
 
6
6
  module RatatuiRuby
7
+ # The Elm Architecture for RatatuiRuby.
7
8
  module Tea
8
- # See RatatuiRuby::Tea::Runtime.run
9
- def self.run: [M, Msg] (
10
- model: M,
11
- view: ^(M model, RatatuiRuby::TUI tui) -> untyped,
12
- update: ^(Msg msg, M model) -> (M | [M, Cmd::execution?] | [M, Cmd::Quit] | [M, nil]),
13
- ?init: ^() -> Msg
14
- ) -> M
9
+ # Starts the MVU event loop.
10
+ def self.run: [Model] (
11
+ model: Model,
12
+ view: ^(Model, RatatuiRuby::TUI) -> (RatatuiRuby::_CustomWidget | RatatuiRuby::widget),
13
+ update: ^(RatatuiRuby::Event, Model) -> Runtime::update_result?,
14
+ ?init: (^() -> untyped)?
15
+ ) -> Model
16
+
17
+ # Wraps a command with a routing prefix.
18
+ def self.route: (Command::execution command, Symbol prefix) -> Command::Mapped
19
+
20
+ # Delegates a prefixed message to a child bag's UPDATE.
21
+ def self.delegate: (
22
+ untyped message,
23
+ Symbol prefix,
24
+ ^(Array[untyped]?, untyped) -> [untyped, Command::execution?] child_update,
25
+ untyped child_model
26
+ ) -> ([untyped, Command::execution?] | nil)
15
27
  end
16
28
  end
data/tasks/steep.rake ADDED
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ #--
4
+ # SPDX-FileCopyrightText: 2026 Kerrick Long <me@kerricklong.com>
5
+ # SPDX-License-Identifier: LGPL-3.0-or-later
6
+ #++
7
+
8
+ desc "Run Steep type checker"
9
+ task :steep do
10
+ sh "bundle exec steep check"
11
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ratatui_ruby-tea
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kerrick Long
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - "~>"
17
17
  - !ruby/object:Gem::Version
18
- version: 0.9.1
18
+ version: 0.10.1
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
- version: 0.9.1
25
+ version: 0.10.1
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: ostruct
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +94,8 @@ files:
94
94
  - Steepfile
95
95
  - doc/concepts/application_architecture.md
96
96
  - doc/concepts/application_testing.md
97
+ - doc/contributors/design/commands_and_outlets.md
98
+ - doc/contributors/kit-no-outlet.md
97
99
  - doc/contributors/priorities.md
98
100
  - doc/custom.css
99
101
  - doc/getting_started/quickstart.md
@@ -123,21 +125,30 @@ files:
123
125
  - exe/.gitkeep
124
126
  - lib/ratatui_ruby/tea.rb
125
127
  - lib/ratatui_ruby/tea/command.rb
128
+ - lib/ratatui_ruby/tea/command/cancellation_token.rb
129
+ - lib/ratatui_ruby/tea/command/custom.rb
130
+ - lib/ratatui_ruby/tea/command/outlet.rb
126
131
  - lib/ratatui_ruby/tea/router.rb
127
132
  - lib/ratatui_ruby/tea/runtime.rb
128
133
  - lib/ratatui_ruby/tea/shortcuts.rb
129
134
  - lib/ratatui_ruby/tea/version.rb
130
135
  - mise.toml
136
+ - rbs_collection.lock.yaml
137
+ - rbs_collection.yaml
131
138
  - sig/examples/verify_readme_usage/app.rbs
132
139
  - sig/examples/widget_command_system/app.rbs
140
+ - sig/open3.rbs
133
141
  - sig/ratatui_ruby/tea.rbs
134
142
  - sig/ratatui_ruby/tea/command.rbs
135
143
  - sig/ratatui_ruby/tea/router.rbs
136
144
  - sig/ratatui_ruby/tea/runtime.rbs
145
+ - sig/ratatui_ruby/tea/shortcuts.rbs
146
+ - sig/ratatui_ruby/tea/version.rbs
137
147
  - tasks/example_viewer.html.erb
138
148
  - tasks/resources/build.yml.erb
139
149
  - tasks/resources/index.html.erb
140
150
  - tasks/resources/rubies.yml
151
+ - tasks/steep.rake
141
152
  - vendor/goodcop/base.yml
142
153
  homepage: https://sr.ht/~kerrick/ratatui_ruby/
143
154
  licenses: