hexastack-cli 0.9.0__tar.gz → 0.10.0__tar.gz
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.
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/PKG-INFO +1 -1
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/pyproject.toml +2 -2
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/pyproject.toml.orig +2 -2
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/adapters/routing.py +6 -2
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/infra/autodiscovery.py +35 -11
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/infra/decorators.py +15 -2
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/README.md +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/__init__.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/adapters/__init__.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/adapters/presenter.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/adapters/suggest.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/domain/__init__.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/domain/config.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/domain/options.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/infra/__init__.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/infra/app.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/infra/bootstrap.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/infra/config.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/infra/options.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/py.typed +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/testing/__init__.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/testing/events.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/testing/narrator.py +0 -0
- {hexastack_cli-0.9.0 → hexastack_cli-0.10.0}/src/hexastack_cli/testing/terminal.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hexastack-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.10.0"
|
|
4
4
|
description = "Hexastack CLI presentation adapter with Typer and Rich"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -24,7 +24,7 @@ testing = ["playwright>=1.49.0"]
|
|
|
24
24
|
cli = "hexastack_cli.infra.bootstrap:CliBootstrapper"
|
|
25
25
|
|
|
26
26
|
[build-system]
|
|
27
|
-
requires = ["uv_build>=0.12.3,<0.
|
|
27
|
+
requires = ["uv_build>=0.12.3,<0.14.0"]
|
|
28
28
|
build-backend = "uv_build"
|
|
29
29
|
|
|
30
30
|
[tool.uv.sources.hexastack-core]
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "hexastack-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.10.0"
|
|
4
4
|
description = "Hexastack CLI presentation adapter with Typer and Rich"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -25,7 +25,7 @@ testing = [
|
|
|
25
25
|
cli = "hexastack_cli.infra.bootstrap:CliBootstrapper"
|
|
26
26
|
|
|
27
27
|
[build-system]
|
|
28
|
-
requires = ["uv_build>=0.12.3,<0.
|
|
28
|
+
requires = ["uv_build>=0.12.3,<0.14.0"]
|
|
29
29
|
build-backend = "uv_build"
|
|
30
30
|
|
|
31
31
|
[tool.uv.sources]
|
|
@@ -307,6 +307,7 @@ def register_cqrs_command(
|
|
|
307
307
|
presenter: RichTerminalPresenter | None = None,
|
|
308
308
|
console: Console | None = None,
|
|
309
309
|
feature_flag: str | None = None,
|
|
310
|
+
hidden: bool = False,
|
|
310
311
|
) -> None:
|
|
311
312
|
"""Register a CQRS Command model as a typed CLI sub-command on a Typer application.
|
|
312
313
|
|
|
@@ -325,6 +326,7 @@ def register_cqrs_command(
|
|
|
325
326
|
presenter: Optional RichTerminalPresenter instance.
|
|
326
327
|
console: Optional rich Console instance.
|
|
327
328
|
feature_flag: Optional feature flag key required for execution.
|
|
329
|
+
hidden: Whether to hide the command from CLI help documentation.
|
|
328
330
|
|
|
329
331
|
Returns:
|
|
330
332
|
None.
|
|
@@ -343,7 +345,7 @@ def register_cqrs_command(
|
|
|
343
345
|
console=console,
|
|
344
346
|
feature_flag=feature_flag,
|
|
345
347
|
)
|
|
346
|
-
app.command(name=cmd_name, help=doc)(runner)
|
|
348
|
+
app.command(name=cmd_name, help=doc, hidden=hidden)(runner)
|
|
347
349
|
|
|
348
350
|
|
|
349
351
|
def register_cqrs_query(
|
|
@@ -357,6 +359,7 @@ def register_cqrs_query(
|
|
|
357
359
|
presenter: RichTerminalPresenter | None = None,
|
|
358
360
|
console: Console | None = None,
|
|
359
361
|
feature_flag: str | None = None,
|
|
362
|
+
hidden: bool = False,
|
|
360
363
|
) -> None:
|
|
361
364
|
"""Register a CQRS Query model as a typed CLI sub-command on a Typer application.
|
|
362
365
|
|
|
@@ -375,6 +378,7 @@ def register_cqrs_query(
|
|
|
375
378
|
presenter: Optional RichTerminalPresenter instance.
|
|
376
379
|
console: Optional rich Console instance.
|
|
377
380
|
feature_flag: Optional feature flag key required for execution.
|
|
381
|
+
hidden: Whether to hide the command from CLI help documentation.
|
|
378
382
|
|
|
379
383
|
Returns:
|
|
380
384
|
None.
|
|
@@ -393,4 +397,4 @@ def register_cqrs_query(
|
|
|
393
397
|
console=console,
|
|
394
398
|
feature_flag=feature_flag,
|
|
395
399
|
)
|
|
396
|
-
app.command(name=qry_name, help=doc)(runner)
|
|
400
|
+
app.command(name=qry_name, help=doc, hidden=hidden)(runner)
|
|
@@ -92,6 +92,7 @@ def _register_model_target(
|
|
|
92
92
|
meta: CliMetadata,
|
|
93
93
|
cmd_name: str,
|
|
94
94
|
help_text: str | None,
|
|
95
|
+
hidden: bool,
|
|
95
96
|
pipeline: ExecutionPipeline,
|
|
96
97
|
console: Console | None,
|
|
97
98
|
) -> None:
|
|
@@ -107,6 +108,7 @@ def _register_model_target(
|
|
|
107
108
|
output_format=meta.output_format,
|
|
108
109
|
console=console,
|
|
109
110
|
feature_flag=meta.feature_flag,
|
|
111
|
+
hidden=hidden,
|
|
110
112
|
)
|
|
111
113
|
elif meta.kind == "query" and issubclass(obj, Query):
|
|
112
114
|
register_cqrs_query(
|
|
@@ -119,9 +121,29 @@ def _register_model_target(
|
|
|
119
121
|
output_format=meta.output_format,
|
|
120
122
|
console=console,
|
|
121
123
|
feature_flag=meta.feature_flag,
|
|
124
|
+
hidden=hidden,
|
|
122
125
|
)
|
|
123
126
|
|
|
124
127
|
|
|
128
|
+
def _resolve_alias_targets(
|
|
129
|
+
group: str | Sequence[str] | None,
|
|
130
|
+
aliases: Sequence[str],
|
|
131
|
+
help_text: str | None,
|
|
132
|
+
) -> list[tuple[list[str], str, str | None]]:
|
|
133
|
+
"""Resolve (group_parts, cmd_name, help) targets for a sequence of aliases."""
|
|
134
|
+
primary_group = _normalize_group_path(group)
|
|
135
|
+
targets: list[tuple[list[str], str, str | None]] = []
|
|
136
|
+
for alias in aliases:
|
|
137
|
+
if alias.startswith("/"):
|
|
138
|
+
targets.append(([], alias.lstrip("/"), help_text))
|
|
139
|
+
elif any(sep in alias for sep in (".", "/", " ")):
|
|
140
|
+
parts = _normalize_group_path(alias)
|
|
141
|
+
targets.append((parts[:-1], parts[-1], help_text))
|
|
142
|
+
else:
|
|
143
|
+
targets.append((primary_group, alias, help_text))
|
|
144
|
+
return targets
|
|
145
|
+
|
|
146
|
+
|
|
125
147
|
def _resolve_targets(
|
|
126
148
|
meta: CliMetadata, default_name: str
|
|
127
149
|
) -> list[tuple[list[str], str, str | None]]:
|
|
@@ -131,16 +153,7 @@ def _resolve_targets(
|
|
|
131
153
|
targets: list[tuple[list[str], str, str | None]] = [
|
|
132
154
|
(primary_group, primary_name, meta.help)
|
|
133
155
|
]
|
|
134
|
-
|
|
135
|
-
for alias in meta.aliases:
|
|
136
|
-
if alias.startswith("/"):
|
|
137
|
-
targets.append(([], alias.lstrip("/"), meta.help))
|
|
138
|
-
elif any(sep in alias for sep in (".", "/", " ")):
|
|
139
|
-
parts = _normalize_group_path(alias)
|
|
140
|
-
targets.append((parts[:-1], parts[-1], meta.help))
|
|
141
|
-
else:
|
|
142
|
-
targets.append((primary_group, alias, meta.help))
|
|
143
|
-
|
|
156
|
+
targets.extend(_resolve_alias_targets(meta.group, meta.aliases, meta.help))
|
|
144
157
|
return targets
|
|
145
158
|
|
|
146
159
|
|
|
@@ -205,11 +218,22 @@ def create_cli_visitor(
|
|
|
205
218
|
|
|
206
219
|
default_name = _to_kebab_case(obj.__name__)
|
|
207
220
|
targets = _resolve_targets(meta, default_name)
|
|
221
|
+
hidden = getattr(meta, "hidden", False)
|
|
208
222
|
|
|
209
223
|
for group_parts, cmd_name, help_text in targets:
|
|
210
224
|
target_app = manager.get_or_create(group_parts)
|
|
211
225
|
_register_model_target(
|
|
212
|
-
target_app, obj, meta, cmd_name, help_text, pipeline, console
|
|
226
|
+
target_app, obj, meta, cmd_name, help_text, hidden, pipeline, console
|
|
227
|
+
)
|
|
228
|
+
|
|
229
|
+
if meta.hidden_aliases:
|
|
230
|
+
hidden_targets = _resolve_alias_targets(
|
|
231
|
+
meta.group, meta.hidden_aliases, meta.help
|
|
213
232
|
)
|
|
233
|
+
for group_parts, cmd_name, help_text in hidden_targets:
|
|
234
|
+
target_app = manager.get_or_create(group_parts)
|
|
235
|
+
_register_model_target(
|
|
236
|
+
target_app, obj, meta, cmd_name, help_text, True, pipeline, console
|
|
237
|
+
)
|
|
214
238
|
|
|
215
239
|
return visitor
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from collections.abc import Callable, Sequence
|
|
2
2
|
from dataclasses import dataclass, field
|
|
3
|
+
from functools import wraps
|
|
3
4
|
from typing import Any, Literal, TypeVar
|
|
4
5
|
|
|
5
6
|
from hexastack_core.domain import Command, Query
|
|
@@ -28,6 +29,8 @@ class CliMetadata:
|
|
|
28
29
|
output_format: str | None = None
|
|
29
30
|
group: str | Sequence[str] | None = None
|
|
30
31
|
feature_flag: str | None = None
|
|
32
|
+
hidden: bool = False
|
|
33
|
+
hidden_aliases: tuple[str, ...] = field(default_factory=tuple)
|
|
31
34
|
|
|
32
35
|
|
|
33
36
|
@dataclass(frozen=True)
|
|
@@ -66,10 +69,12 @@ def cli_command(
|
|
|
66
69
|
*,
|
|
67
70
|
positional: Sequence[str] | str | None = None,
|
|
68
71
|
aliases: Sequence[str] | str | None = None,
|
|
72
|
+
hidden_aliases: Sequence[str] | str | None = None,
|
|
69
73
|
help: str | None = None,
|
|
70
74
|
output_format: str | None = None,
|
|
71
75
|
group: str | Sequence[str] | None = None,
|
|
72
76
|
feature_flag: str | None = None,
|
|
77
|
+
hidden: bool = False,
|
|
73
78
|
) -> Callable[[type[TCommand]], type[TCommand]]:
|
|
74
79
|
"""Decorator marking a Command class for automatic CLI command exposure.
|
|
75
80
|
|
|
@@ -77,10 +82,12 @@ def cli_command(
|
|
|
77
82
|
name: Optional custom CLI command name (defaults to kebab-cased class name).
|
|
78
83
|
positional: Optional field name or list of field names to treat as positional CLI arguments.
|
|
79
84
|
aliases: Optional alias or list of aliases (can be intra-group like 'create' or cross-group like 'account.new').
|
|
85
|
+
hidden_aliases: Optional alias or list of aliases to register with hidden=True.
|
|
80
86
|
help: Optional help text for the command.
|
|
81
87
|
output_format: Optional presenter output format.
|
|
82
88
|
group: Optional sub-command group name or nested group path (e.g. 'user', 'user.profile').
|
|
83
89
|
feature_flag: Optional feature flag key required to execute the command.
|
|
90
|
+
hidden: Whether to hide the command from terminal --help displays.
|
|
84
91
|
|
|
85
92
|
Returns:
|
|
86
93
|
Decorated Command class with attached CLI metadata.
|
|
@@ -95,10 +102,12 @@ def cli_command(
|
|
|
95
102
|
name=name,
|
|
96
103
|
positional=_normalize_tokens(positional),
|
|
97
104
|
aliases=_normalize_tokens(aliases),
|
|
105
|
+
hidden_aliases=_normalize_tokens(hidden_aliases),
|
|
98
106
|
help=help,
|
|
99
107
|
output_format=output_format,
|
|
100
108
|
group=group,
|
|
101
109
|
feature_flag=feature_flag,
|
|
110
|
+
hidden=hidden,
|
|
102
111
|
)
|
|
103
112
|
setattr(cls, _CLI_METADATA_ATTR, meta)
|
|
104
113
|
return cls
|
|
@@ -137,10 +146,12 @@ def cli_query(
|
|
|
137
146
|
*,
|
|
138
147
|
positional: Sequence[str] | str | None = None,
|
|
139
148
|
aliases: Sequence[str] | str | None = None,
|
|
149
|
+
hidden_aliases: Sequence[str] | str | None = None,
|
|
140
150
|
help: str | None = None,
|
|
141
151
|
output_format: str | None = None,
|
|
142
152
|
group: str | Sequence[str] | None = None,
|
|
143
153
|
feature_flag: str | None = None,
|
|
154
|
+
hidden: bool = False,
|
|
144
155
|
) -> Callable[[type[TQuery]], type[TQuery]]:
|
|
145
156
|
"""Decorator marking a Query class for automatic CLI command exposure.
|
|
146
157
|
|
|
@@ -148,10 +159,12 @@ def cli_query(
|
|
|
148
159
|
name: Optional custom CLI command name (defaults to kebab-cased class name).
|
|
149
160
|
positional: Optional field name or list of field names to treat as positional CLI arguments.
|
|
150
161
|
aliases: Optional alias or list of aliases (can be intra-group like 'find' or cross-group like 'search.user').
|
|
162
|
+
hidden_aliases: Optional alias or list of aliases to register with hidden=True.
|
|
151
163
|
help: Optional help text for the command.
|
|
152
164
|
output_format: Optional presenter output format.
|
|
153
165
|
group: Optional sub-command group name or nested group path (e.g. 'user', 'user.profile').
|
|
154
166
|
feature_flag: Optional feature flag key required to execute the command.
|
|
167
|
+
hidden: Whether to hide the query command from terminal --help displays.
|
|
155
168
|
|
|
156
169
|
Returns:
|
|
157
170
|
Decorated Query class with attached CLI metadata.
|
|
@@ -166,10 +179,12 @@ def cli_query(
|
|
|
166
179
|
name=name,
|
|
167
180
|
positional=_normalize_tokens(positional),
|
|
168
181
|
aliases=_normalize_tokens(aliases),
|
|
182
|
+
hidden_aliases=_normalize_tokens(hidden_aliases),
|
|
169
183
|
help=help,
|
|
170
184
|
output_format=output_format,
|
|
171
185
|
group=group,
|
|
172
186
|
feature_flag=feature_flag,
|
|
187
|
+
hidden=hidden,
|
|
173
188
|
)
|
|
174
189
|
setattr(cls, _CLI_METADATA_ATTR, meta)
|
|
175
190
|
return cls
|
|
@@ -195,8 +210,6 @@ def feature_flag_command(
|
|
|
195
210
|
Returns:
|
|
196
211
|
Decorator wrapping the target callable.
|
|
197
212
|
"""
|
|
198
|
-
from functools import wraps
|
|
199
|
-
|
|
200
213
|
import typer
|
|
201
214
|
|
|
202
215
|
from hexastack_core.adapters.feature_flags.config import ConfigFeatureFlagAdapter
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|