falyx 0.1.25__py3-none-any.whl → 0.1.27__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.
falyx/action/__init__.py CHANGED
@@ -21,6 +21,7 @@ from .menu_action import MenuAction
21
21
  from .select_file_action import SelectFileAction
22
22
  from .selection_action import SelectionAction
23
23
  from .signal_action import SignalAction
24
+ from .user_input_action import UserInputAction
24
25
 
25
26
  __all__ = [
26
27
  "Action",
@@ -38,4 +39,5 @@ __all__ = [
38
39
  "SignalAction",
39
40
  "FallbackAction",
40
41
  "LiteralInputAction",
42
+ "UserInputAction",
41
43
  ]
@@ -11,6 +11,7 @@ from falyx.hook_manager import HookType
11
11
  from falyx.logger import logger
12
12
  from falyx.protocols import ActionFactoryProtocol
13
13
  from falyx.themes import OneColors
14
+ from falyx.utils import ensure_async
14
15
 
15
16
 
16
17
  class ActionFactoryAction(BaseAction):
@@ -46,6 +47,14 @@ class ActionFactoryAction(BaseAction):
46
47
  self.preview_args = preview_args
47
48
  self.preview_kwargs = preview_kwargs or {}
48
49
 
50
+ @property
51
+ def factory(self) -> ActionFactoryProtocol:
52
+ return self._factory # type: ignore[return-value]
53
+
54
+ @factory.setter
55
+ def factory(self, value: ActionFactoryProtocol):
56
+ self._factory = ensure_async(value)
57
+
49
58
  async def _run(self, *args, **kwargs) -> Any:
50
59
  updated_kwargs = self._maybe_inject_last_result(kwargs)
51
60
  context = ExecutionContext(
@@ -57,7 +66,7 @@ class ActionFactoryAction(BaseAction):
57
66
  context.start_timer()
58
67
  try:
59
68
  await self.hooks.trigger(HookType.BEFORE, context)
60
- generated_action = self.factory(*args, **updated_kwargs)
69
+ generated_action = await self.factory(*args, **updated_kwargs)
61
70
  if not isinstance(generated_action, BaseAction):
62
71
  raise TypeError(
63
72
  f"[{self.name}] Factory must return a BaseAction, got "
@@ -94,7 +103,7 @@ class ActionFactoryAction(BaseAction):
94
103
  tree = parent.add(label) if parent else Tree(label)
95
104
 
96
105
  try:
97
- generated = self.factory(*self.preview_args, **self.preview_kwargs)
106
+ generated = await self.factory(*self.preview_args, **self.preview_kwargs)
98
107
  if isinstance(generated, BaseAction):
99
108
  await generated.preview(parent=tree)
100
109
  else:
@@ -38,6 +38,7 @@ class MenuAction(BaseAction):
38
38
  never_prompt: bool = False,
39
39
  include_reserved: bool = True,
40
40
  show_table: bool = True,
41
+ custom_table: Table | None = None,
41
42
  ):
42
43
  super().__init__(
43
44
  name,
@@ -54,8 +55,11 @@ class MenuAction(BaseAction):
54
55
  self.prompt_session = prompt_session or PromptSession()
55
56
  self.include_reserved = include_reserved
56
57
  self.show_table = show_table
58
+ self.custom_table = custom_table
57
59
 
58
60
  def _build_table(self) -> Table:
61
+ if self.custom_table:
62
+ return self.custom_table
59
63
  table = render_table_base(
60
64
  title=self.title,
61
65
  columns=self.columns,
@@ -0,0 +1,94 @@
1
+ from prompt_toolkit import PromptSession
2
+ from prompt_toolkit.validation import Validator
3
+ from rich.console import Console
4
+ from rich.tree import Tree
5
+
6
+ from falyx.action import BaseAction
7
+ from falyx.context import ExecutionContext
8
+ from falyx.execution_registry import ExecutionRegistry as er
9
+ from falyx.hook_manager import HookType
10
+ from falyx.themes.colors import OneColors
11
+
12
+
13
+ class UserInputAction(BaseAction):
14
+ """
15
+ Prompts the user for input via PromptSession and returns the result.
16
+
17
+ Args:
18
+ name (str): Action name.
19
+ prompt_text (str): Prompt text (can include '{last_result}' for interpolation).
20
+ validator (Validator, optional): Prompt Toolkit validator.
21
+ console (Console, optional): Rich console for rendering.
22
+ prompt_session (PromptSession, optional): Reusable prompt session.
23
+ inject_last_result (bool): Whether to inject last_result into prompt.
24
+ inject_into (str): Key to use for injection (default: 'last_result').
25
+ """
26
+
27
+ def __init__(
28
+ self,
29
+ name: str,
30
+ *,
31
+ prompt_text: str = "Input > ",
32
+ validator: Validator | None = None,
33
+ console: Console | None = None,
34
+ prompt_session: PromptSession | None = None,
35
+ inject_last_result: bool = False,
36
+ ):
37
+ super().__init__(
38
+ name=name,
39
+ inject_last_result=inject_last_result,
40
+ )
41
+ self.prompt_text = prompt_text
42
+ self.validator = validator
43
+ self.console = console or Console(color_system="auto")
44
+ self.prompt_session = prompt_session or PromptSession()
45
+
46
+ async def _run(self, *args, **kwargs) -> str:
47
+ context = ExecutionContext(
48
+ name=self.name,
49
+ args=args,
50
+ kwargs=kwargs,
51
+ action=self,
52
+ )
53
+ context.start_timer()
54
+ try:
55
+ await self.hooks.trigger(HookType.BEFORE, context)
56
+
57
+ prompt_text = self.prompt_text
58
+ if self.inject_last_result and self.last_result:
59
+ prompt_text = prompt_text.format(last_result=self.last_result)
60
+
61
+ answer = await self.prompt_session.prompt_async(
62
+ prompt_text,
63
+ validator=self.validator,
64
+ )
65
+ context.result = answer
66
+ await self.hooks.trigger(HookType.ON_SUCCESS, context)
67
+ return answer
68
+ except Exception as error:
69
+ context.exception = error
70
+ await self.hooks.trigger(HookType.ON_ERROR, context)
71
+ raise
72
+ finally:
73
+ context.stop_timer()
74
+ await self.hooks.trigger(HookType.AFTER, context)
75
+ await self.hooks.trigger(HookType.ON_TEARDOWN, context)
76
+ er.record(context)
77
+
78
+ async def preview(self, parent: Tree | None = None):
79
+ label = f"[{OneColors.MAGENTA}]⌨ UserInputAction[/] '{self.name}'"
80
+ tree = parent.add(label) if parent else Tree(label)
81
+
82
+ prompt_text = (
83
+ self.prompt_text.replace("{last_result}", "<last_result>")
84
+ if "{last_result}" in self.prompt_text
85
+ else self.prompt_text
86
+ )
87
+ tree.add(f"[dim]Prompt:[/] {prompt_text}")
88
+ if self.validator:
89
+ tree.add("[dim]Validator:[/] Yes")
90
+ if not parent:
91
+ self.console.print(tree)
92
+
93
+ def __str__(self):
94
+ return f"UserInputAction(name={self.name!r}, prompt={self.prompt!r})"
falyx/command.py CHANGED
@@ -30,7 +30,6 @@ from falyx.action.action import Action, ActionGroup, BaseAction, ChainedAction
30
30
  from falyx.action.io_action import BaseIOAction
31
31
  from falyx.context import ExecutionContext
32
32
  from falyx.debug import register_debug_hooks
33
- from falyx.exceptions import FalyxError
34
33
  from falyx.execution_registry import ExecutionRegistry as er
35
34
  from falyx.hook_manager import HookManager, HookType
36
35
  from falyx.logger import logger
@@ -38,8 +37,9 @@ from falyx.options_manager import OptionsManager
38
37
  from falyx.prompt_utils import confirm_async, should_prompt_user
39
38
  from falyx.retry import RetryPolicy
40
39
  from falyx.retry_utils import enable_retries_recursively
40
+ from falyx.signals import CancelSignal
41
41
  from falyx.themes import OneColors
42
- from falyx.utils import _noop, ensure_async
42
+ from falyx.utils import ensure_async
43
43
 
44
44
  console = Console(color_system="auto")
45
45
 
@@ -98,7 +98,7 @@ class Command(BaseModel):
98
98
 
99
99
  key: str
100
100
  description: str
101
- action: BaseAction | Callable[[], Any] = _noop
101
+ action: BaseAction | Callable[[], Any]
102
102
  args: tuple = ()
103
103
  kwargs: dict[str, Any] = Field(default_factory=dict)
104
104
  hidden: bool = False
@@ -205,7 +205,7 @@ class Command(BaseModel):
205
205
  await self.preview()
206
206
  if not await confirm_async(self.confirmation_prompt):
207
207
  logger.info("[Command:%s] ❌ Cancelled by user.", self.key)
208
- raise FalyxError(f"[Command:{self.key}] Cancelled by confirmation.")
208
+ raise CancelSignal(f"[Command:{self.key}] Cancelled by confirmation.")
209
209
 
210
210
  context.start_timer()
211
211
 
falyx/config.py CHANGED
@@ -72,10 +72,10 @@ class RawCommand(BaseModel):
72
72
  description: str
73
73
  action: str
74
74
 
75
- args: tuple[Any, ...] = ()
76
- kwargs: dict[str, Any] = {}
77
- aliases: list[str] = []
78
- tags: list[str] = []
75
+ args: tuple[Any, ...] = Field(default_factory=tuple)
76
+ kwargs: dict[str, Any] = Field(default_factory=dict)
77
+ aliases: list[str] = Field(default_factory=list)
78
+ tags: list[str] = Field(default_factory=list)
79
79
  style: str = OneColors.WHITE
80
80
 
81
81
  confirm: bool = False
@@ -86,13 +86,13 @@ class RawCommand(BaseModel):
86
86
  spinner_message: str = "Processing..."
87
87
  spinner_type: str = "dots"
88
88
  spinner_style: str = OneColors.CYAN
89
- spinner_kwargs: dict[str, Any] = {}
89
+ spinner_kwargs: dict[str, Any] = Field(default_factory=dict)
90
90
 
91
- before_hooks: list[Callable] = []
92
- success_hooks: list[Callable] = []
93
- error_hooks: list[Callable] = []
94
- after_hooks: list[Callable] = []
95
- teardown_hooks: list[Callable] = []
91
+ before_hooks: list[Callable] = Field(default_factory=list)
92
+ success_hooks: list[Callable] = Field(default_factory=list)
93
+ error_hooks: list[Callable] = Field(default_factory=list)
94
+ after_hooks: list[Callable] = Field(default_factory=list)
95
+ teardown_hooks: list[Callable] = Field(default_factory=list)
96
96
 
97
97
  logging_hooks: bool = False
98
98
  retry: bool = False
@@ -129,6 +129,60 @@ def convert_commands(raw_commands: list[dict[str, Any]]) -> list[Command]:
129
129
  return commands
130
130
 
131
131
 
132
+ def convert_submenus(
133
+ raw_submenus: list[dict[str, Any]], *, parent_path: Path | None = None, depth: int = 0
134
+ ) -> list[dict[str, Any]]:
135
+ submenus: list[dict[str, Any]] = []
136
+ for raw_submenu in raw_submenus:
137
+ if raw_submenu.get("config"):
138
+ config_path = Path(raw_submenu["config"])
139
+ if parent_path:
140
+ config_path = (parent_path.parent / config_path).resolve()
141
+ submenu = loader(config_path, _depth=depth + 1)
142
+ else:
143
+ submenu_module_path = raw_submenu.get("submenu")
144
+ if not isinstance(submenu_module_path, str):
145
+ console.print(
146
+ f"[{OneColors.DARK_RED}]❌ Invalid submenu path:[/] {submenu_module_path}"
147
+ )
148
+ sys.exit(1)
149
+ submenu = import_action(submenu_module_path)
150
+ if not isinstance(submenu, Falyx):
151
+ console.print(f"[{OneColors.DARK_RED}]❌ Invalid submenu:[/] {submenu}")
152
+ sys.exit(1)
153
+
154
+ key = raw_submenu.get("key")
155
+ if not isinstance(key, str):
156
+ console.print(f"[{OneColors.DARK_RED}]❌ Invalid submenu key:[/] {key}")
157
+ sys.exit(1)
158
+
159
+ description = raw_submenu.get("description")
160
+ if not isinstance(description, str):
161
+ console.print(
162
+ f"[{OneColors.DARK_RED}]❌ Invalid submenu description:[/] {description}"
163
+ )
164
+ sys.exit(1)
165
+
166
+ submenus.append(
167
+ Submenu(
168
+ key=key,
169
+ description=description,
170
+ submenu=submenu,
171
+ style=raw_submenu.get("style", OneColors.CYAN),
172
+ ).model_dump()
173
+ )
174
+ return submenus
175
+
176
+
177
+ class Submenu(BaseModel):
178
+ """Submenu model for Falyx CLI configuration."""
179
+
180
+ key: str
181
+ description: str
182
+ submenu: Any
183
+ style: str = OneColors.CYAN
184
+
185
+
132
186
  class FalyxConfig(BaseModel):
133
187
  """Falyx CLI configuration model."""
134
188
 
@@ -140,6 +194,7 @@ class FalyxConfig(BaseModel):
140
194
  welcome_message: str = ""
141
195
  exit_message: str = ""
142
196
  commands: list[Command] | list[dict] = []
197
+ submenus: list[dict[str, Any]] = []
143
198
 
144
199
  @model_validator(mode="after")
145
200
  def validate_prompt_format(self) -> FalyxConfig:
@@ -160,10 +215,12 @@ class FalyxConfig(BaseModel):
160
215
  exit_message=self.exit_message,
161
216
  )
162
217
  flx.add_commands(self.commands)
218
+ for submenu in self.submenus:
219
+ flx.add_submenu(**submenu)
163
220
  return flx
164
221
 
165
222
 
166
- def loader(file_path: Path | str) -> Falyx:
223
+ def loader(file_path: Path | str, _depth: int = 0) -> Falyx:
167
224
  """
168
225
  Load Falyx CLI configuration from a YAML or TOML file.
169
226
 
@@ -183,6 +240,9 @@ def loader(file_path: Path | str) -> Falyx:
183
240
  Raises:
184
241
  ValueError: If the file format is unsupported or file cannot be parsed.
185
242
  """
243
+ if _depth > 5:
244
+ raise ValueError("Maximum submenu depth exceeded (5 levels deep)")
245
+
186
246
  if isinstance(file_path, (str, Path)):
187
247
  path = Path(file_path)
188
248
  else:
@@ -212,6 +272,7 @@ def loader(file_path: Path | str) -> Falyx:
212
272
  )
213
273
 
214
274
  commands = convert_commands(raw_config["commands"])
275
+ submenus = convert_submenus(raw_config.get("submenus", []))
215
276
  return FalyxConfig(
216
277
  title=raw_config.get("title", f"[{OneColors.BLUE_b}]Falyx CLI"),
217
278
  prompt=raw_config.get("prompt", [(OneColors.BLUE_b, "FALYX > ")]),
@@ -219,4 +280,5 @@ def loader(file_path: Path | str) -> Falyx:
219
280
  welcome_message=raw_config.get("welcome_message", ""),
220
281
  exit_message=raw_config.get("exit_message", ""),
221
282
  commands=commands,
283
+ submenus=submenus,
222
284
  ).to_falyx()
@@ -100,7 +100,7 @@ class ExecutionRegistry:
100
100
 
101
101
  @classmethod
102
102
  def summary(cls):
103
- table = Table(title="[📊] Execution History", expand=True, box=box.SIMPLE)
103
+ table = Table(title="📊 Execution History", expand=True, box=box.SIMPLE)
104
104
 
105
105
  table.add_column("Name", style="bold cyan")
106
106
  table.add_column("Start", justify="right", style="dim")
falyx/falyx.py CHANGED
@@ -19,6 +19,8 @@ for running commands, actions, and workflows. It supports:
19
19
  Falyx enables building flexible, robust, and user-friendly
20
20
  terminal applications with minimal boilerplate.
21
21
  """
22
+ from __future__ import annotations
23
+
22
24
  import asyncio
23
25
  import logging
24
26
  import sys
@@ -55,9 +57,9 @@ from falyx.logger import logger
55
57
  from falyx.options_manager import OptionsManager
56
58
  from falyx.parsers import get_arg_parsers
57
59
  from falyx.retry import RetryPolicy
58
- from falyx.signals import BackSignal, QuitSignal
60
+ from falyx.signals import BackSignal, CancelSignal, QuitSignal
59
61
  from falyx.themes import OneColors, get_nord_theme
60
- from falyx.utils import CaseInsensitiveDict, chunks, get_program_invocation
62
+ from falyx.utils import CaseInsensitiveDict, _noop, chunks, get_program_invocation
61
63
  from falyx.version import __version__
62
64
 
63
65
 
@@ -235,8 +237,9 @@ class Falyx:
235
237
  def _get_exit_command(self) -> Command:
236
238
  """Returns the back command for the menu."""
237
239
  return Command(
238
- key="Q",
240
+ key="X",
239
241
  description="Exit",
242
+ action=Action("Exit", action=_noop),
240
243
  aliases=["EXIT", "QUIT"],
241
244
  style=OneColors.DARK_RED,
242
245
  )
@@ -264,9 +267,9 @@ class Falyx:
264
267
  help_text += " [dim](requires input)[/dim]"
265
268
  table.add_row(
266
269
  f"[{command.style}]{command.key}[/]",
267
- ", ".join(command.aliases) if command.aliases else "None",
270
+ ", ".join(command.aliases) if command.aliases else "",
268
271
  help_text,
269
- ", ".join(command.tags) if command.tags else "None",
272
+ ", ".join(command.tags) if command.tags else "",
270
273
  )
271
274
 
272
275
  table.add_row(
@@ -303,7 +306,7 @@ class Falyx:
303
306
  key="H",
304
307
  aliases=["HELP", "?"],
305
308
  description="Help",
306
- action=self._show_help,
309
+ action=Action("Help", self._show_help),
307
310
  style=OneColors.LIGHT_YELLOW,
308
311
  )
309
312
 
@@ -505,18 +508,19 @@ class Falyx:
505
508
 
506
509
  def update_exit_command(
507
510
  self,
508
- key: str = "Q",
511
+ key: str = "X",
509
512
  description: str = "Exit",
510
513
  aliases: list[str] | None = None,
511
- action: Callable[[], Any] = lambda: None,
514
+ action: Callable[[], Any] | None = None,
512
515
  style: str = OneColors.DARK_RED,
513
516
  confirm: bool = False,
514
517
  confirm_message: str = "Are you sure?",
515
518
  ) -> None:
516
519
  """Updates the back command of the menu."""
520
+ self._validate_command_key(key)
521
+ action = action or Action(description, action=_noop)
517
522
  if not callable(action):
518
523
  raise InvalidActionError("Action must be a callable.")
519
- self._validate_command_key(key)
520
524
  self.exit_command = Command(
521
525
  key=key,
522
526
  description=description,
@@ -528,14 +532,15 @@ class Falyx:
528
532
  )
529
533
 
530
534
  def add_submenu(
531
- self, key: str, description: str, submenu: "Falyx", *, style: str = OneColors.CYAN
535
+ self, key: str, description: str, submenu: Falyx, *, style: str = OneColors.CYAN
532
536
  ) -> None:
533
537
  """Adds a submenu to the menu."""
534
538
  if not isinstance(submenu, Falyx):
535
539
  raise NotAFalyxError("submenu must be an instance of Falyx.")
536
540
  self._validate_command_key(key)
537
541
  self.add_command(key, description, submenu.menu, style=style)
538
- submenu.update_exit_command(key="B", description="Back", aliases=["BACK"])
542
+ if submenu.exit_command.key == "X":
543
+ submenu.update_exit_command(key="B", description="Back", aliases=["BACK"])
539
544
 
540
545
  def add_commands(self, commands: list[Command] | list[dict]) -> None:
541
546
  """Adds a list of Command instances or config dicts."""
@@ -915,6 +920,8 @@ class Falyx:
915
920
  break
916
921
  except BackSignal:
917
922
  logger.info("BackSignal received.")
923
+ except CancelSignal:
924
+ logger.info("CancelSignal received.")
918
925
  finally:
919
926
  logger.info("Exiting menu: %s", self.get_title())
920
927
  if self.exit_message:
falyx/protocols.py CHANGED
@@ -2,10 +2,10 @@
2
2
  """protocols.py"""
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Protocol
5
+ from typing import Any, Awaitable, Protocol
6
6
 
7
7
  from falyx.action.action import BaseAction
8
8
 
9
9
 
10
10
  class ActionFactoryProtocol(Protocol):
11
- def __call__(self, *args: Any, **kwargs: Any) -> BaseAction: ...
11
+ async def __call__(self, *args: Any, **kwargs: Any) -> Awaitable[BaseAction]: ...
falyx/signals.py CHANGED
@@ -22,3 +22,10 @@ class BackSignal(FlowSignal):
22
22
 
23
23
  def __init__(self, message: str = "Back signal received."):
24
24
  super().__init__(message)
25
+
26
+
27
+ class CancelSignal(FlowSignal):
28
+ """Raised to cancel the current command or action."""
29
+
30
+ def __init__(self, message: str = "Cancel signal received."):
31
+ super().__init__(message)
falyx/utils.py CHANGED
@@ -48,6 +48,7 @@ def ensure_async(function: Callable[..., T]) -> Callable[..., Awaitable[T]]:
48
48
 
49
49
  if not callable(function):
50
50
  raise TypeError(f"{function} is not callable")
51
+
51
52
  return async_wrapper
52
53
 
53
54
 
falyx/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.25"
1
+ __version__ = "0.1.27"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: falyx
3
- Version: 0.1.25
3
+ Version: 0.1.27
4
4
  Summary: Reliable and introspectable async CLI action framework.
5
5
  License: MIT
6
6
  Author: Roland Thomas Jr
@@ -1,25 +1,26 @@
1
1
  falyx/.pytyped,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
2
  falyx/__init__.py,sha256=L40665QyjAqHQxHdxxY2_yPeDa4p0LE7Nu_2dkm08Ls,650
3
3
  falyx/__main__.py,sha256=g_LwJieofK3DJzCYtpkAMEeOXhzSLQenb7pRVUqcf-Y,2152
4
- falyx/action/__init__.py,sha256=P3Eh0lE2VunzxqwfLbZKxE6FEcdR_u5OROkDTBYgeP0,904
4
+ falyx/action/__init__.py,sha256=zpOK5g4DybydV8d3QI0Zq52aWaKFPYi-J6szAQTsQ2c,974
5
5
  falyx/action/action.py,sha256=CJB9eeeEqBGkZHjMpG24eXHRjouKSfESCI1zWzoE7JQ,32488
6
- falyx/action/action_factory.py,sha256=qhlx8-BAEiNDJrbzF0HZzipY09Ple6J7FxxNvoBda9Y,4228
6
+ falyx/action/action_factory.py,sha256=qNtEnsbKsNl-WijChbTQYfdI3k14fN-1bzDsGFx8yZI,4517
7
7
  falyx/action/http_action.py,sha256=aIieGHyZSkz1ZGay-fwgDYZ0QF17XypAWtKeVAYp5f4,5806
8
8
  falyx/action/io_action.py,sha256=zdDq07zSLlaShBQ3ztXTRC6aZL0JoERNZSmvHy1V22w,9718
9
- falyx/action/menu_action.py,sha256=8qttPuq0AUh_oFaa3A82e19dSl4ZhQ9Y_j5CU7zHAlc,5532
9
+ falyx/action/menu_action.py,sha256=cboCpXyl0fZUxpFsvEPu0dGhFfr_vdfllceQnICA0gU,5683
10
10
  falyx/action/select_file_action.py,sha256=hHLhmTSacWaUXhRTeIIiXt8gR7zbjkXJ2MAkKQYCpp4,7799
11
11
  falyx/action/selection_action.py,sha256=22rF7UqRrQAMjGIheDqAbUizVMBg9aCl9e4VOLLZZJo,8811
12
12
  falyx/action/signal_action.py,sha256=5UMqvzy7fBnLANGwYUWoe1VRhrr7e-yOVeLdOnCBiJo,1350
13
13
  falyx/action/types.py,sha256=iVD-bHm1GRXOTIlHOeT_KcDBRZm4Hz5Xzl_BOalvEf4,961
14
+ falyx/action/user_input_action.py,sha256=LSTzC_3TfsfXdz-qV3GlOIGpZWAOgO9J5DnNsHO7ee8,3398
14
15
  falyx/bottom_bar.py,sha256=iWxgOKWgn5YmREeZBuGA50FzqzEfz1-Vnqm0V_fhldc,7383
15
- falyx/command.py,sha256=s7r9aeUYEk9iUNE69JQtlFoPx9AehTxkHMPxpLKVIOA,12238
16
- falyx/config.py,sha256=yg5KHkiZh4sNOPrkqL-ym0YrMUomBqUSyuOcXFOp6Ew,7204
16
+ falyx/command.py,sha256=CeleZJ039996d6qn895JXagLeh7gMZltx7jABecjSXY,12224
17
+ falyx/config.py,sha256=8dkQfL-Ro-vWw1AcO2fD1PGZ92Cyfnwl885ZlpLkp4Y,9636
17
18
  falyx/config_schema.py,sha256=j5GQuHVlaU-VLxLF9t8idZRjqOP9MIKp1hyd9NhpAGU,3124
18
19
  falyx/context.py,sha256=FNF-IS7RMDxel2l3kskEqQImZ0mLO6zvGw_xC9cIzgI,10338
19
20
  falyx/debug.py,sha256=oWWTLOF8elrx_RGZ1G4pbzfFr46FjB0woFXpVU2wmjU,1567
20
21
  falyx/exceptions.py,sha256=Qxp6UScZWEyno-6Lgksrv3s9iwjbr2U-d6hun-_xpc0,798
21
- falyx/execution_registry.py,sha256=re56TImfL67p30ZlVBjqxz9Nn34SD4gvTlwFVPSzVCM,4712
22
- falyx/falyx.py,sha256=cSCVtLsW8n5ZfRvjxVTJF5Rf3Qg1pNWWVqRdqSHTEGo,40545
22
+ falyx/execution_registry.py,sha256=rctsz0mrIHPToLZqylblVjDdKWdq1x_JBc8GwMP5sJ8,4710
23
+ falyx/falyx.py,sha256=ECL6nDgqxS0s8lzOlMnBOSqwZEsLN0kYzeBCs0lUsYI,40860
23
24
  falyx/hook_manager.py,sha256=GuGxVVz9FXrU39Tk220QcsLsMXeut7ZDkGW3hU9GcwQ,2952
24
25
  falyx/hooks.py,sha256=IV2nbj5FjY2m3_L7x4mYBnaRDG45E8tWQU90i4butlw,2940
25
26
  falyx/init.py,sha256=abcSlPmxVeByLIHdUkNjqtO_tEkO3ApC6f9WbxsSEWg,3393
@@ -28,19 +29,19 @@ falyx/menu.py,sha256=faxGgocqQYY6HtzVbenHaFj8YqsmycBEyziC8Ahzqjo,2870
28
29
  falyx/options_manager.py,sha256=dFAnQw543tQ6Xupvh1PwBrhiSWlSACHw8K-sHP_lUh4,2842
29
30
  falyx/parsers.py,sha256=hxrBouQEqdgk6aWzNa7UwTg7u55vJffSEUUTiiQoI0U,5602
30
31
  falyx/prompt_utils.py,sha256=qgk0bXs7mwzflqzWyFhEOTpKQ_ZtMIqGhKeg-ocwNnE,1542
31
- falyx/protocols.py,sha256=dXNS-kh-5XB92PE5POy4uJ4KLT0O3ZAoiqw55jgR2IM,306
32
+ falyx/protocols.py,sha256=ejSz18D8Qg63ONdgwbvn2YanKK9bGF0e3Bjxh9y3Buc,334
32
33
  falyx/retry.py,sha256=UUzY6FlKobr84Afw7yJO9rj3AIQepDk2fcWs6_1gi6Q,3788
33
34
  falyx/retry_utils.py,sha256=EAzc-ECTu8AxKkmlw28ioOW9y-Y9tLQ0KasvSkBRYgs,694
34
35
  falyx/selection.py,sha256=l2LLISqgP8xfHdcTAEbTTqs_Bae4-LVUKMN7VQH7tM0,10731
35
- falyx/signals.py,sha256=4PTuVRB_P_aWfnU8pANqhMxGTLq7TJDEyk9jCp0Bx2c,713
36
+ falyx/signals.py,sha256=PGlc0Cm8DfUB3lCf58u_kwTwm2XUEFQ2joFq0Qc_GXI,906
36
37
  falyx/tagged_table.py,sha256=4SV-SdXFrAhy1JNToeBCvyxT-iWVf6cWY7XETTys4n8,1067
37
38
  falyx/themes/__init__.py,sha256=1CZhEUCin9cUk8IGYBUFkVvdHRNNJBEFXccHwpUKZCA,284
38
39
  falyx/themes/colors.py,sha256=4aaeAHJetmeNInI0Zytg4E3YqKfPFelpf04vtjSvsS8,19776
39
- falyx/utils.py,sha256=uss-FV8p164pmhoqYtQt8gNp5z8fGbuMAk4dRJ6RopI,6717
40
+ falyx/utils.py,sha256=u3puR4Bh-unNBw9a0V9sw7PDTIzRaNLolap0oz5bVIk,6718
40
41
  falyx/validators.py,sha256=t5iyzVpY8tdC4rfhr4isEfWpD5gNTzjeX_Hbi_Uq6sA,1328
41
- falyx/version.py,sha256=Ej7LsXg-6CASlaEHsZkUoLDpYEfHeFKdIeXMIM0esgA,23
42
- falyx-0.1.25.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
43
- falyx-0.1.25.dist-info/METADATA,sha256=ZFvg_e4wFYKOB5f85YQswxEk1bQ9H3Eg6di63jcLrkU,5521
44
- falyx-0.1.25.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
45
- falyx-0.1.25.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
46
- falyx-0.1.25.dist-info/RECORD,,
42
+ falyx/version.py,sha256=vEF032D64gj-9WJp4kp0yS1eFIq4XHIqJr91sJJNwWg,23
43
+ falyx-0.1.27.dist-info/LICENSE,sha256=B0yqgaHuSdhN7T3OBmgQSiDTy8HqT5Oe_dLypRe4Ra4,1073
44
+ falyx-0.1.27.dist-info/METADATA,sha256=rs1IR_MPVQKge3QAZjwHUbh3sOfIutI5qckcMIaVR5w,5521
45
+ falyx-0.1.27.dist-info/WHEEL,sha256=fGIA9gx4Qxk2KDKeNJCbOEwSrmLtjWCwzBz351GyrPQ,88
46
+ falyx-0.1.27.dist-info/entry_points.txt,sha256=j8owOSl2j1Ss8DtGMnKfgehKaolqnIPhVFHaUBLUnMs,45
47
+ falyx-0.1.27.dist-info/RECORD,,
File without changes