falyx 0.1.23__py3-none-any.whl → 0.1.25__py3-none-any.whl

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.
Files changed (44) hide show
  1. falyx/__init__.py +1 -1
  2. falyx/action/__init__.py +41 -0
  3. falyx/{action.py → action/action.py} +41 -23
  4. falyx/{action_factory.py → action/action_factory.py} +17 -5
  5. falyx/{http_action.py → action/http_action.py} +10 -9
  6. falyx/{io_action.py → action/io_action.py} +19 -14
  7. falyx/{menu_action.py → action/menu_action.py} +9 -79
  8. falyx/{select_file_action.py → action/select_file_action.py} +5 -36
  9. falyx/{selection_action.py → action/selection_action.py} +22 -8
  10. falyx/action/signal_action.py +43 -0
  11. falyx/action/types.py +37 -0
  12. falyx/bottom_bar.py +3 -3
  13. falyx/command.py +13 -10
  14. falyx/config.py +17 -9
  15. falyx/context.py +16 -8
  16. falyx/debug.py +2 -1
  17. falyx/exceptions.py +3 -0
  18. falyx/execution_registry.py +59 -13
  19. falyx/falyx.py +67 -77
  20. falyx/hook_manager.py +20 -3
  21. falyx/hooks.py +13 -6
  22. falyx/init.py +1 -0
  23. falyx/logger.py +5 -0
  24. falyx/menu.py +85 -0
  25. falyx/options_manager.py +7 -3
  26. falyx/parsers.py +2 -2
  27. falyx/prompt_utils.py +30 -1
  28. falyx/protocols.py +2 -1
  29. falyx/retry.py +23 -12
  30. falyx/retry_utils.py +2 -1
  31. falyx/selection.py +7 -3
  32. falyx/signals.py +3 -0
  33. falyx/tagged_table.py +2 -1
  34. falyx/themes/__init__.py +15 -0
  35. falyx/utils.py +11 -39
  36. falyx/validators.py +8 -7
  37. falyx/version.py +1 -1
  38. {falyx-0.1.23.dist-info → falyx-0.1.25.dist-info}/METADATA +2 -1
  39. falyx-0.1.25.dist-info/RECORD +46 -0
  40. falyx/signal_action.py +0 -30
  41. falyx-0.1.23.dist-info/RECORD +0 -41
  42. {falyx-0.1.23.dist-info → falyx-0.1.25.dist-info}/LICENSE +0 -0
  43. {falyx-0.1.23.dist-info → falyx-0.1.25.dist-info}/WHEEL +0 -0
  44. {falyx-0.1.23.dist-info → falyx-0.1.25.dist-info}/entry_points.txt +0 -0
@@ -6,10 +6,11 @@ from prompt_toolkit import PromptSession
6
6
  from rich.console import Console
7
7
  from rich.tree import Tree
8
8
 
9
- from falyx.action import BaseAction
9
+ from falyx.action.action import BaseAction
10
10
  from falyx.context import ExecutionContext
11
11
  from falyx.execution_registry import ExecutionRegistry as er
12
12
  from falyx.hook_manager import HookType
13
+ from falyx.logger import logger
13
14
  from falyx.selection import (
14
15
  SelectionOption,
15
16
  prompt_for_index,
@@ -17,11 +18,19 @@ from falyx.selection import (
17
18
  render_selection_dict_table,
18
19
  render_selection_indexed_table,
19
20
  )
20
- from falyx.themes.colors import OneColors
21
- from falyx.utils import CaseInsensitiveDict, logger
21
+ from falyx.themes import OneColors
22
+ from falyx.utils import CaseInsensitiveDict
22
23
 
23
24
 
24
25
  class SelectionAction(BaseAction):
26
+ """
27
+ A selection action that prompts the user to select an option from a list or
28
+ dictionary. The selected option is then returned as the result of the action.
29
+
30
+ If return_key is True, the key of the selected option is returned instead of
31
+ the value.
32
+ """
33
+
25
34
  def __init__(
26
35
  self,
27
36
  name: str,
@@ -45,7 +54,8 @@ class SelectionAction(BaseAction):
45
54
  inject_into=inject_into,
46
55
  never_prompt=never_prompt,
47
56
  )
48
- self.selections: list[str] | CaseInsensitiveDict = selections
57
+ # Setter normalizes to correct type, mypy can't infer that
58
+ self.selections: list[str] | CaseInsensitiveDict = selections # type: ignore[assignment]
49
59
  self.return_key = return_key
50
60
  self.title = title
51
61
  self.columns = columns
@@ -71,7 +81,8 @@ class SelectionAction(BaseAction):
71
81
  self._selections = cid
72
82
  else:
73
83
  raise TypeError(
74
- f"'selections' must be a list[str] or dict[str, SelectionOption], got {type(value).__name__}"
84
+ "'selections' must be a list[str] or dict[str, SelectionOption], "
85
+ f"got {type(value).__name__}"
75
86
  )
76
87
 
77
88
  async def _run(self, *args, **kwargs) -> Any:
@@ -108,7 +119,8 @@ class SelectionAction(BaseAction):
108
119
 
109
120
  if self.never_prompt and not effective_default:
110
121
  raise ValueError(
111
- f"[{self.name}] 'never_prompt' is True but no valid default_selection was provided."
122
+ f"[{self.name}] 'never_prompt' is True but no valid default_selection "
123
+ "was provided."
112
124
  )
113
125
 
114
126
  context.start_timer()
@@ -152,7 +164,8 @@ class SelectionAction(BaseAction):
152
164
  result = key if self.return_key else self.selections[key].value
153
165
  else:
154
166
  raise TypeError(
155
- f"'selections' must be a list[str] or dict[str, tuple[str, Any]], got {type(self.selections).__name__}"
167
+ "'selections' must be a list[str] or dict[str, tuple[str, Any]], "
168
+ f"got {type(self.selections).__name__}"
156
169
  )
157
170
  context.result = result
158
171
  await self.hooks.trigger(HookType.ON_SUCCESS, context)
@@ -205,5 +218,6 @@ class SelectionAction(BaseAction):
205
218
  return (
206
219
  f"SelectionAction(name={self.name!r}, type={selection_type}, "
207
220
  f"default_selection={self.default_selection!r}, "
208
- f"return_key={self.return_key}, prompt={'off' if self.never_prompt else 'on'})"
221
+ f"return_key={self.return_key}, "
222
+ f"prompt={'off' if self.never_prompt else 'on'})"
209
223
  )
@@ -0,0 +1,43 @@
1
+ # Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
2
+ """signal_action.py"""
3
+ from rich.tree import Tree
4
+
5
+ from falyx.action.action import Action
6
+ from falyx.signals import FlowSignal
7
+ from falyx.themes import OneColors
8
+
9
+
10
+ class SignalAction(Action):
11
+ """
12
+ An action that raises a control flow signal when executed.
13
+
14
+ Useful for exiting a menu, going back, or halting execution gracefully.
15
+ """
16
+
17
+ def __init__(self, name: str, signal: Exception):
18
+ self.signal = signal
19
+ super().__init__(name, action=self.raise_signal)
20
+
21
+ async def raise_signal(self, *args, **kwargs):
22
+ raise self.signal
23
+
24
+ @property
25
+ def signal(self):
26
+ return self._signal
27
+
28
+ @signal.setter
29
+ def signal(self, value: FlowSignal):
30
+ if not isinstance(value, FlowSignal):
31
+ raise TypeError(
32
+ f"Signal must be an FlowSignal instance, got {type(value).__name__}"
33
+ )
34
+ self._signal = value
35
+
36
+ def __str__(self):
37
+ return f"SignalAction(name={self.name}, signal={self._signal.__class__.__name__})"
38
+
39
+ async def preview(self, parent: Tree | None = None):
40
+ label = f"[{OneColors.LIGHT_RED}]⚡ SignalAction[/] '{self.signal.__class__.__name__}'"
41
+ tree = parent.add(label) if parent else Tree(label)
42
+ if not parent:
43
+ self.console.print(tree)
falyx/action/types.py ADDED
@@ -0,0 +1,37 @@
1
+ from __future__ import annotations
2
+
3
+ from enum import Enum
4
+
5
+
6
+ class FileReturnType(Enum):
7
+ """Enum for file return types."""
8
+
9
+ TEXT = "text"
10
+ PATH = "path"
11
+ JSON = "json"
12
+ TOML = "toml"
13
+ YAML = "yaml"
14
+ CSV = "csv"
15
+ TSV = "tsv"
16
+ XML = "xml"
17
+
18
+ @classmethod
19
+ def _get_alias(cls, value: str) -> str:
20
+ aliases = {
21
+ "yml": "yaml",
22
+ "txt": "text",
23
+ "file": "path",
24
+ "filepath": "path",
25
+ }
26
+ return aliases.get(value, value)
27
+
28
+ @classmethod
29
+ def _missing_(cls, value: object) -> FileReturnType:
30
+ if isinstance(value, str):
31
+ normalized = value.lower()
32
+ alias = cls._get_alias(normalized)
33
+ for member in cls:
34
+ if member.value == alias:
35
+ return member
36
+ valid = ", ".join(member.value for member in cls)
37
+ raise ValueError(f"Invalid FileReturnType: '{value}'. Must be one of: {valid}")
falyx/bottom_bar.py CHANGED
@@ -8,7 +8,7 @@ from prompt_toolkit.key_binding import KeyBindings
8
8
  from rich.console import Console
9
9
 
10
10
  from falyx.options_manager import OptionsManager
11
- from falyx.themes.colors import OneColors
11
+ from falyx.themes import OneColors
12
12
  from falyx.utils import CaseInsensitiveDict, chunks
13
13
 
14
14
 
@@ -146,7 +146,7 @@ class BottomBar:
146
146
  for k in (key.upper(), key.lower()):
147
147
 
148
148
  @self.key_bindings.add(k)
149
- def _(event):
149
+ def _(_):
150
150
  toggle_state()
151
151
 
152
152
  def add_toggle_from_option(
@@ -204,6 +204,6 @@ class BottomBar:
204
204
  """Render the bottom bar."""
205
205
  lines = []
206
206
  for chunk in chunks(self._named_items.values(), self.columns):
207
- lines.extend([fn for fn in chunk])
207
+ lines.extend(list(chunk))
208
208
  lines.append(lambda: HTML("\n"))
209
209
  return merge_formatted_text([fn() for fn in lines[:-1]])
falyx/command.py CHANGED
@@ -26,19 +26,20 @@ from pydantic import BaseModel, ConfigDict, Field, PrivateAttr, field_validator
26
26
  from rich.console import Console
27
27
  from rich.tree import Tree
28
28
 
29
- from falyx.action import Action, ActionGroup, BaseAction, ChainedAction
29
+ from falyx.action.action import Action, ActionGroup, BaseAction, ChainedAction
30
+ from falyx.action.io_action import BaseIOAction
30
31
  from falyx.context import ExecutionContext
31
32
  from falyx.debug import register_debug_hooks
32
33
  from falyx.exceptions import FalyxError
33
34
  from falyx.execution_registry import ExecutionRegistry as er
34
35
  from falyx.hook_manager import HookManager, HookType
35
- from falyx.io_action import BaseIOAction
36
+ from falyx.logger import logger
36
37
  from falyx.options_manager import OptionsManager
37
- from falyx.prompt_utils import should_prompt_user
38
+ from falyx.prompt_utils import confirm_async, should_prompt_user
38
39
  from falyx.retry import RetryPolicy
39
40
  from falyx.retry_utils import enable_retries_recursively
40
- from falyx.themes.colors import OneColors
41
- from falyx.utils import _noop, confirm_async, ensure_async, logger
41
+ from falyx.themes import OneColors
42
+ from falyx.utils import _noop, ensure_async
42
43
 
43
44
  console = Console(color_system="auto")
44
45
 
@@ -134,7 +135,7 @@ class Command(BaseModel):
134
135
  return ensure_async(action)
135
136
  raise TypeError("Action must be a callable or an instance of BaseAction")
136
137
 
137
- def model_post_init(self, __context: Any) -> None:
138
+ def model_post_init(self, _: Any) -> None:
138
139
  """Post-initialization to set up the action and hooks."""
139
140
  if self.retry and isinstance(self.action, Action):
140
141
  self.action.enable_retry()
@@ -142,14 +143,16 @@ class Command(BaseModel):
142
143
  self.action.set_retry_policy(self.retry_policy)
143
144
  elif self.retry:
144
145
  logger.warning(
145
- f"[Command:{self.key}] Retry requested, but action is not an Action instance."
146
+ "[Command:%s] Retry requested, but action is not an Action instance.",
147
+ self.key,
146
148
  )
147
149
  if self.retry_all and isinstance(self.action, BaseAction):
148
150
  self.retry_policy.enabled = True
149
151
  enable_retries_recursively(self.action, self.retry_policy)
150
152
  elif self.retry_all:
151
153
  logger.warning(
152
- f"[Command:{self.key}] Retry all requested, but action is not a BaseAction instance."
154
+ "[Command:%s] Retry all requested, but action is not a BaseAction.",
155
+ self.key,
153
156
  )
154
157
 
155
158
  if self.logging_hooks and isinstance(self.action, BaseAction):
@@ -201,7 +204,7 @@ class Command(BaseModel):
201
204
  if self.preview_before_confirm:
202
205
  await self.preview()
203
206
  if not await confirm_async(self.confirmation_prompt):
204
- logger.info(f"[Command:{self.key}] ❌ Cancelled by user.")
207
+ logger.info("[Command:%s] ❌ Cancelled by user.", self.key)
205
208
  raise FalyxError(f"[Command:{self.key}] Cancelled by confirmation.")
206
209
 
207
210
  context.start_timer()
@@ -288,7 +291,7 @@ class Command(BaseModel):
288
291
  if self.help_text:
289
292
  console.print(f"[dim]💡 {self.help_text}[/dim]")
290
293
  console.print(
291
- f"[{OneColors.DARK_RED}]⚠️ Action is not callable or lacks a preview method.[/]"
294
+ f"[{OneColors.DARK_RED}]⚠️ No preview available for this action.[/]"
292
295
  )
293
296
 
294
297
  def __str__(self) -> str:
falyx/config.py CHANGED
@@ -13,12 +13,12 @@ import yaml
13
13
  from pydantic import BaseModel, Field, field_validator, model_validator
14
14
  from rich.console import Console
15
15
 
16
- from falyx.action import Action, BaseAction
16
+ from falyx.action.action import Action, BaseAction
17
17
  from falyx.command import Command
18
18
  from falyx.falyx import Falyx
19
+ from falyx.logger import logger
19
20
  from falyx.retry import RetryPolicy
20
- from falyx.themes.colors import OneColors
21
- from falyx.utils import logger
21
+ from falyx.themes import OneColors
22
22
 
23
23
  console = Console(color_system="auto")
24
24
 
@@ -47,7 +47,8 @@ def import_action(dotted_path: str) -> Any:
47
47
  logger.error("Failed to import module '%s': %s", module_path, error)
48
48
  console.print(
49
49
  f"[{OneColors.DARK_RED}]❌ Could not import '{dotted_path}': {error}[/]\n"
50
- f"[{OneColors.COMMENT_GREY}]Ensure the module is installed and discoverable via PYTHONPATH."
50
+ f"[{OneColors.COMMENT_GREY}]Ensure the module is installed and discoverable "
51
+ "via PYTHONPATH."
51
52
  )
52
53
  sys.exit(1)
53
54
  try:
@@ -57,13 +58,16 @@ def import_action(dotted_path: str) -> Any:
57
58
  "Module '%s' does not have attribute '%s': %s", module_path, attr, error
58
59
  )
59
60
  console.print(
60
- f"[{OneColors.DARK_RED}]❌ Module '{module_path}' has no attribute '{attr}': {error}[/]"
61
+ f"[{OneColors.DARK_RED}]❌ Module '{module_path}' has no attribute "
62
+ f"'{attr}': {error}[/]"
61
63
  )
62
64
  sys.exit(1)
63
65
  return action
64
66
 
65
67
 
66
68
  class RawCommand(BaseModel):
69
+ """Raw command model for Falyx CLI configuration."""
70
+
67
71
  key: str
68
72
  description: str
69
73
  action: str
@@ -72,7 +76,7 @@ class RawCommand(BaseModel):
72
76
  kwargs: dict[str, Any] = {}
73
77
  aliases: list[str] = []
74
78
  tags: list[str] = []
75
- style: str = "white"
79
+ style: str = OneColors.WHITE
76
80
 
77
81
  confirm: bool = False
78
82
  confirm_message: str = "Are you sure?"
@@ -81,7 +85,7 @@ class RawCommand(BaseModel):
81
85
  spinner: bool = False
82
86
  spinner_message: str = "Processing..."
83
87
  spinner_type: str = "dots"
84
- spinner_style: str = "cyan"
88
+ spinner_style: str = OneColors.CYAN
85
89
  spinner_kwargs: dict[str, Any] = {}
86
90
 
87
91
  before_hooks: list[Callable] = []
@@ -126,6 +130,8 @@ def convert_commands(raw_commands: list[dict[str, Any]]) -> list[Command]:
126
130
 
127
131
 
128
132
  class FalyxConfig(BaseModel):
133
+ """Falyx CLI configuration model."""
134
+
129
135
  title: str = "Falyx CLI"
130
136
  prompt: str | list[tuple[str, str]] | list[list[str]] = [
131
137
  (OneColors.BLUE_b, "FALYX > ")
@@ -148,7 +154,7 @@ class FalyxConfig(BaseModel):
148
154
  def to_falyx(self) -> Falyx:
149
155
  flx = Falyx(
150
156
  title=self.title,
151
- prompt=self.prompt,
157
+ prompt=self.prompt, # type: ignore[arg-type]
152
158
  columns=self.columns,
153
159
  welcome_message=self.welcome_message,
154
160
  exit_message=self.exit_message,
@@ -159,7 +165,9 @@ class FalyxConfig(BaseModel):
159
165
 
160
166
  def loader(file_path: Path | str) -> Falyx:
161
167
  """
162
- Load command definitions from a YAML or TOML file.
168
+ Load Falyx CLI configuration from a YAML or TOML file.
169
+
170
+ The file should contain a dictionary with a list of commands.
163
171
 
164
172
  Each command should be defined as a dictionary with at least:
165
173
  - key: a unique single-character key
falyx/context.py CHANGED
@@ -29,10 +29,10 @@ class ExecutionContext(BaseModel):
29
29
  """
30
30
  Represents the runtime metadata and state for a single action execution.
31
31
 
32
- The `ExecutionContext` tracks arguments, results, exceptions, timing, and additional
33
- metadata for each invocation of a Falyx `BaseAction`. It provides integration with the
34
- Falyx hook system and execution registry, enabling lifecycle management, diagnostics,
35
- and structured logging.
32
+ The `ExecutionContext` tracks arguments, results, exceptions, timing, and
33
+ additional metadata for each invocation of a Falyx `BaseAction`. It provides
34
+ integration with the Falyx hook system and execution registry, enabling lifecycle
35
+ management, diagnostics, and structured logging.
36
36
 
37
37
  Attributes:
38
38
  name (str): The name of the action being executed.
@@ -47,7 +47,8 @@ class ExecutionContext(BaseModel):
47
47
  end_wall (datetime | None): Wall-clock timestamp when execution ended.
48
48
  extra (dict): Metadata for custom introspection or special use by Actions.
49
49
  console (Console): Rich console instance for logging or UI output.
50
- shared_context (SharedContext | None): Optional shared context when running in a chain or group.
50
+ shared_context (SharedContext | None): Optional shared context when running in
51
+ a chain or group.
51
52
 
52
53
  Properties:
53
54
  duration (float | None): The execution duration in seconds.
@@ -95,7 +96,11 @@ class ExecutionContext(BaseModel):
95
96
  self.end_wall = datetime.now()
96
97
 
97
98
  def get_shared_context(self) -> SharedContext:
98
- return self.shared_context or SharedContext(name="default")
99
+ if not self.shared_context:
100
+ raise ValueError(
101
+ "SharedContext is not set. This context is not part of a chain or group."
102
+ )
103
+ return self.shared_context
99
104
 
100
105
  @property
101
106
  def duration(self) -> float | None:
@@ -190,8 +195,10 @@ class SharedContext(BaseModel):
190
195
  errors (list[tuple[int, Exception]]): Indexed list of errors from failed actions.
191
196
  current_index (int): Index of the currently executing action (used in chains).
192
197
  is_parallel (bool): Whether the context is used in parallel mode (ActionGroup).
193
- shared_result (Any | None): Optional shared value available to all actions in parallel mode.
194
- share (dict[str, Any]): Custom shared key-value store for user-defined communication
198
+ shared_result (Any | None): Optional shared value available to all actions in
199
+ parallel mode.
200
+ share (dict[str, Any]): Custom shared key-value store for user-defined
201
+ communication
195
202
  between actions (e.g., flags, intermediate data, settings).
196
203
 
197
204
  Note:
@@ -208,6 +215,7 @@ class SharedContext(BaseModel):
208
215
  """
209
216
 
210
217
  name: str
218
+ action: Any
211
219
  results: list[Any] = Field(default_factory=list)
212
220
  errors: list[tuple[int, Exception]] = Field(default_factory=list)
213
221
  current_index: int = -1
falyx/debug.py CHANGED
@@ -1,7 +1,8 @@
1
1
  # Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
2
+ """debug.py"""
2
3
  from falyx.context import ExecutionContext
3
4
  from falyx.hook_manager import HookManager, HookType
4
- from falyx.utils import logger
5
+ from falyx.logger import logger
5
6
 
6
7
 
7
8
  def log_before(context: ExecutionContext):
falyx/exceptions.py CHANGED
@@ -1,4 +1,7 @@
1
1
  # Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
2
+ """exceptions.py"""
3
+
4
+
2
5
  class FalyxError(Exception):
3
6
  """Custom exception for the Menu class."""
4
7
 
@@ -1,5 +1,32 @@
1
1
  # Falyx CLI Framework — (c) 2025 rtj.dev LLC — MIT Licensed
2
- """execution_registry.py"""
2
+ """
3
+ execution_registry.py
4
+
5
+ This module provides the `ExecutionRegistry`, a global class for tracking and
6
+ introspecting the execution history of Falyx actions.
7
+
8
+ The registry captures `ExecutionContext` instances from all executed actions, making it
9
+ easy to debug, audit, and visualize workflow behavior over time. It supports retrieval,
10
+ filtering, clearing, and formatted summary display.
11
+
12
+ Core Features:
13
+ - Stores all action execution contexts globally (with access by name).
14
+ - Provides live execution summaries in a rich table format.
15
+ - Enables creation of a built-in Falyx Action to print history on demand.
16
+ - Integrates with Falyx's introspectable and hook-driven execution model.
17
+
18
+ Intended for:
19
+ - Debugging and diagnostics
20
+ - Post-run inspection of CLI workflows
21
+ - Interactive tools built with Falyx
22
+
23
+ Example:
24
+ from falyx.execution_registry import ExecutionRegistry as er
25
+ er.record(context)
26
+ er.summary()
27
+ """
28
+ from __future__ import annotations
29
+
3
30
  from collections import defaultdict
4
31
  from datetime import datetime
5
32
  from typing import Dict, List
@@ -9,11 +36,40 @@ from rich.console import Console
9
36
  from rich.table import Table
10
37
 
11
38
  from falyx.context import ExecutionContext
12
- from falyx.themes.colors import OneColors
13
- from falyx.utils import logger
39
+ from falyx.logger import logger
40
+ from falyx.themes import OneColors
14
41
 
15
42
 
16
43
  class ExecutionRegistry:
44
+ """
45
+ Global registry for recording and inspecting Falyx action executions.
46
+
47
+ This class captures every `ExecutionContext` generated by a Falyx `Action`,
48
+ `ChainedAction`, or `ActionGroup`, maintaining both full history and
49
+ name-indexed access for filtered analysis.
50
+
51
+ Methods:
52
+ - record(context): Stores an ExecutionContext, logging a summary line.
53
+ - get_all(): Returns the list of all recorded executions.
54
+ - get_by_name(name): Returns all executions with the given action name.
55
+ - get_latest(): Returns the most recent execution.
56
+ - clear(): Wipes the registry for a fresh run.
57
+ - summary(): Renders a formatted Rich table of all execution results.
58
+
59
+ Use Cases:
60
+ - Debugging chained or factory-generated workflows
61
+ - Viewing results and exceptions from multiple runs
62
+ - Embedding a diagnostic command into your CLI for user support
63
+
64
+ Note:
65
+ This registry is in-memory and not persistent. It's reset each time the process
66
+ restarts or `clear()` is called.
67
+
68
+ Example:
69
+ ExecutionRegistry.record(context)
70
+ ExecutionRegistry.summary()
71
+ """
72
+
17
73
  _store_by_name: Dict[str, List[ExecutionContext]] = defaultdict(list)
18
74
  _store_all: List[ExecutionContext] = []
19
75
  _console = Console(color_system="auto")
@@ -78,13 +134,3 @@ class ExecutionRegistry:
78
134
  table.add_row(ctx.name, start, end, duration, status, result)
79
135
 
80
136
  cls._console.print(table)
81
-
82
- @classmethod
83
- def get_history_action(cls) -> "Action":
84
- """Return an Action that prints the execution summary."""
85
- from falyx.action import Action
86
-
87
- async def show_history():
88
- cls.summary()
89
-
90
- return Action(name="View Execution History", action=show_history)