bijux-cli 0.1.0__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.
- bijux_cli/__init__.py +39 -0
- bijux_cli/__main__.py +417 -0
- bijux_cli/__version__.py +42 -0
- bijux_cli/api.py +326 -0
- bijux_cli/cli.py +68 -0
- bijux_cli/commands/__init__.py +170 -0
- bijux_cli/commands/audit.py +293 -0
- bijux_cli/commands/config/__init__.py +85 -0
- bijux_cli/commands/config/clear.py +124 -0
- bijux_cli/commands/config/export.py +148 -0
- bijux_cli/commands/config/get.py +141 -0
- bijux_cli/commands/config/list_cmd.py +127 -0
- bijux_cli/commands/config/load.py +128 -0
- bijux_cli/commands/config/py.typed +0 -0
- bijux_cli/commands/config/reload.py +125 -0
- bijux_cli/commands/config/service.py +107 -0
- bijux_cli/commands/config/set.py +260 -0
- bijux_cli/commands/config/unset.py +140 -0
- bijux_cli/commands/dev/__init__.py +46 -0
- bijux_cli/commands/dev/di.py +285 -0
- bijux_cli/commands/dev/list_plugins.py +66 -0
- bijux_cli/commands/dev/py.typed +0 -0
- bijux_cli/commands/dev/service.py +120 -0
- bijux_cli/commands/docs.py +329 -0
- bijux_cli/commands/doctor.py +181 -0
- bijux_cli/commands/help.py +436 -0
- bijux_cli/commands/history/__init__.py +43 -0
- bijux_cli/commands/history/clear.py +160 -0
- bijux_cli/commands/history/py.typed +0 -0
- bijux_cli/commands/history/service.py +362 -0
- bijux_cli/commands/memory/__init__.py +59 -0
- bijux_cli/commands/memory/clear.py +114 -0
- bijux_cli/commands/memory/delete.py +144 -0
- bijux_cli/commands/memory/get.py +146 -0
- bijux_cli/commands/memory/list.py +115 -0
- bijux_cli/commands/memory/py.typed +0 -0
- bijux_cli/commands/memory/service.py +242 -0
- bijux_cli/commands/memory/set.py +136 -0
- bijux_cli/commands/memory/utils.py +54 -0
- bijux_cli/commands/plugins/__init__.py +59 -0
- bijux_cli/commands/plugins/check.py +240 -0
- bijux_cli/commands/plugins/info.py +143 -0
- bijux_cli/commands/plugins/install.py +327 -0
- bijux_cli/commands/plugins/list.py +73 -0
- bijux_cli/commands/plugins/py.typed +0 -0
- bijux_cli/commands/plugins/scaffold.py +287 -0
- bijux_cli/commands/plugins/uninstall.py +206 -0
- bijux_cli/commands/plugins/utils.py +158 -0
- bijux_cli/commands/py.typed +0 -0
- bijux_cli/commands/repl.py +709 -0
- bijux_cli/commands/sleep.py +169 -0
- bijux_cli/commands/status.py +289 -0
- bijux_cli/commands/utilities.py +637 -0
- bijux_cli/commands/version.py +152 -0
- bijux_cli/contracts/__init__.py +48 -0
- bijux_cli/contracts/audit.py +66 -0
- bijux_cli/contracts/config.py +127 -0
- bijux_cli/contracts/context.py +93 -0
- bijux_cli/contracts/docs.py +65 -0
- bijux_cli/contracts/doctor.py +32 -0
- bijux_cli/contracts/emitter.py +58 -0
- bijux_cli/contracts/history.py +101 -0
- bijux_cli/contracts/memory.py +76 -0
- bijux_cli/contracts/observability.py +94 -0
- bijux_cli/contracts/process.py +48 -0
- bijux_cli/contracts/py.typed +0 -0
- bijux_cli/contracts/registry.py +115 -0
- bijux_cli/contracts/retry.py +53 -0
- bijux_cli/contracts/serializer.py +100 -0
- bijux_cli/contracts/telemetry.py +46 -0
- bijux_cli/core/__init__.py +44 -0
- bijux_cli/core/constants.py +21 -0
- bijux_cli/core/context.py +218 -0
- bijux_cli/core/di.py +695 -0
- bijux_cli/core/engine.py +199 -0
- bijux_cli/core/enums.py +52 -0
- bijux_cli/core/exceptions.py +184 -0
- bijux_cli/core/paths.py +21 -0
- bijux_cli/core/py.typed +0 -0
- bijux_cli/httpapi.py +552 -0
- bijux_cli/infra/__init__.py +43 -0
- bijux_cli/infra/emitter.py +140 -0
- bijux_cli/infra/observability.py +148 -0
- bijux_cli/infra/process.py +177 -0
- bijux_cli/infra/py.typed +0 -0
- bijux_cli/infra/retry.py +300 -0
- bijux_cli/infra/serializer.py +573 -0
- bijux_cli/infra/telemetry.py +159 -0
- bijux_cli/py.typed +0 -0
- bijux_cli/services/__init__.py +233 -0
- bijux_cli/services/audit.py +268 -0
- bijux_cli/services/config.py +677 -0
- bijux_cli/services/docs.py +170 -0
- bijux_cli/services/doctor.py +34 -0
- bijux_cli/services/history.py +527 -0
- bijux_cli/services/memory.py +129 -0
- bijux_cli/services/plugins/__init__.py +346 -0
- bijux_cli/services/plugins/entrypoints.py +151 -0
- bijux_cli/services/plugins/groups.py +177 -0
- bijux_cli/services/plugins/hooks.py +113 -0
- bijux_cli/services/plugins/py.typed +0 -0
- bijux_cli/services/plugins/registry.py +284 -0
- bijux_cli/services/py.typed +0 -0
- bijux_cli/services/utils.py +68 -0
- bijux_cli-0.1.0.dist-info/METADATA +297 -0
- bijux_cli-0.1.0.dist-info/RECORD +108 -0
- bijux_cli-0.1.0.dist-info/WHEEL +4 -0
- bijux_cli-0.1.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright © 2025 Bijan Mousavi
|
|
3
|
+
|
|
4
|
+
"""Implements the `config set` subcommand for the Bijux CLI.
|
|
5
|
+
|
|
6
|
+
This module contains the logic for creating or updating a key-value pair in
|
|
7
|
+
the active configuration store. It accepts input either as a direct argument
|
|
8
|
+
or from stdin, performs strict validation on keys and values, and provides a
|
|
9
|
+
structured, machine-readable response.
|
|
10
|
+
|
|
11
|
+
Output Contract:
|
|
12
|
+
* Success: `{"status": "updated", "key": str, "value": str}`
|
|
13
|
+
* Verbose: Adds `{"python": str, "platform": str}` to the payload.
|
|
14
|
+
* Error: `{"error": str, "code": int}`
|
|
15
|
+
|
|
16
|
+
Exit Codes:
|
|
17
|
+
* `0`: Success.
|
|
18
|
+
* `1`: An unexpected error occurred, such as a file lock or write failure.
|
|
19
|
+
* `2`: An invalid argument was provided (e.g., malformed pair, invalid key).
|
|
20
|
+
* `3`: The key, value, or configuration path contained non-ASCII or forbidden
|
|
21
|
+
control characters.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from contextlib import suppress
|
|
27
|
+
import os
|
|
28
|
+
import platform
|
|
29
|
+
import re
|
|
30
|
+
import string
|
|
31
|
+
import sys
|
|
32
|
+
|
|
33
|
+
import typer
|
|
34
|
+
|
|
35
|
+
from bijux_cli.commands.utilities import (
|
|
36
|
+
ascii_safe,
|
|
37
|
+
emit_error_and_exit,
|
|
38
|
+
new_run_command,
|
|
39
|
+
parse_global_flags,
|
|
40
|
+
)
|
|
41
|
+
from bijux_cli.contracts import ConfigProtocol
|
|
42
|
+
from bijux_cli.core.constants import (
|
|
43
|
+
HELP_DEBUG,
|
|
44
|
+
HELP_FORMAT,
|
|
45
|
+
HELP_NO_PRETTY,
|
|
46
|
+
HELP_QUIET,
|
|
47
|
+
HELP_VERBOSE,
|
|
48
|
+
)
|
|
49
|
+
from bijux_cli.core.di import DIContainer
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def set_config(
|
|
53
|
+
ctx: typer.Context,
|
|
54
|
+
pair: str | None = typer.Argument(
|
|
55
|
+
None, help="KEY=VALUE to set; if omitted, read from stdin"
|
|
56
|
+
),
|
|
57
|
+
quiet: bool = typer.Option(False, "-q", "--quiet", help=HELP_QUIET),
|
|
58
|
+
verbose: bool = typer.Option(False, "-v", "--verbose", help=HELP_VERBOSE),
|
|
59
|
+
fmt: str = typer.Option("json", "-f", "--format", help=HELP_FORMAT),
|
|
60
|
+
pretty: bool = typer.Option(True, "--pretty/--no-pretty", help=HELP_NO_PRETTY),
|
|
61
|
+
debug: bool = typer.Option(False, "-d", "--debug", help=HELP_DEBUG),
|
|
62
|
+
) -> None:
|
|
63
|
+
"""Sets or updates a configuration key-value pair.
|
|
64
|
+
|
|
65
|
+
This function orchestrates the `set` operation. It accepts a `KEY=VALUE`
|
|
66
|
+
pair from either a command-line argument or standard input. It performs
|
|
67
|
+
extensive validation on the key and value for format and content, handles
|
|
68
|
+
file locking to prevent race conditions, and emits a structured payload
|
|
69
|
+
confirming the update.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
ctx (typer.Context): The Typer context for the CLI.
|
|
73
|
+
pair (str | None): A string in "KEY=VALUE" format. If None, the pair
|
|
74
|
+
is read from stdin.
|
|
75
|
+
quiet (bool): If True, suppresses all output except for errors.
|
|
76
|
+
verbose (bool): If True, includes Python/platform details in the output.
|
|
77
|
+
fmt (str): The output format, "json" or "yaml".
|
|
78
|
+
pretty (bool): If True, pretty-prints the output.
|
|
79
|
+
debug (bool): If True, enables debug diagnostics.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
None:
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
SystemExit: Always exits with a contract-compliant status code and
|
|
86
|
+
payload, indicating success or detailing the error.
|
|
87
|
+
"""
|
|
88
|
+
cfg_path = os.environ.get("BIJUXCLI_CONFIG", "") or ""
|
|
89
|
+
if cfg_path:
|
|
90
|
+
try:
|
|
91
|
+
cfg_path.encode("ascii")
|
|
92
|
+
except UnicodeEncodeError:
|
|
93
|
+
emit_error_and_exit(
|
|
94
|
+
"Non-ASCII characters in config path",
|
|
95
|
+
code=3,
|
|
96
|
+
failure="ascii",
|
|
97
|
+
command="config set",
|
|
98
|
+
fmt="json",
|
|
99
|
+
quiet=False,
|
|
100
|
+
include_runtime=False,
|
|
101
|
+
debug=False,
|
|
102
|
+
extra={"path": "[non-ascii path provided]"},
|
|
103
|
+
)
|
|
104
|
+
flags = parse_global_flags()
|
|
105
|
+
quiet = flags["quiet"]
|
|
106
|
+
verbose = flags["verbose"]
|
|
107
|
+
fmt = flags["format"]
|
|
108
|
+
pretty = flags["pretty"]
|
|
109
|
+
debug = flags["debug"]
|
|
110
|
+
include_runtime = verbose
|
|
111
|
+
fmt_lower = fmt.lower()
|
|
112
|
+
command = "config set"
|
|
113
|
+
if os.name == "posix":
|
|
114
|
+
with suppress(Exception):
|
|
115
|
+
import fcntl
|
|
116
|
+
|
|
117
|
+
with open(cfg_path, "a+") as fh:
|
|
118
|
+
try:
|
|
119
|
+
fcntl.flock(fh, fcntl.LOCK_EX | fcntl.LOCK_NB)
|
|
120
|
+
except OSError:
|
|
121
|
+
emit_error_and_exit(
|
|
122
|
+
"Config file is locked",
|
|
123
|
+
code=1,
|
|
124
|
+
failure="file_locked",
|
|
125
|
+
command=command,
|
|
126
|
+
fmt=fmt_lower,
|
|
127
|
+
quiet=quiet,
|
|
128
|
+
include_runtime=include_runtime,
|
|
129
|
+
debug=debug,
|
|
130
|
+
extra={"path": cfg_path},
|
|
131
|
+
)
|
|
132
|
+
finally:
|
|
133
|
+
with suppress(Exception):
|
|
134
|
+
fcntl.flock(fh, fcntl.LOCK_UN)
|
|
135
|
+
if pair is None:
|
|
136
|
+
if sys.stdin.isatty():
|
|
137
|
+
emit_error_and_exit(
|
|
138
|
+
"Missing argument: KEY=VALUE required",
|
|
139
|
+
code=2,
|
|
140
|
+
failure="missing_argument",
|
|
141
|
+
command=command,
|
|
142
|
+
fmt=fmt_lower,
|
|
143
|
+
quiet=quiet,
|
|
144
|
+
include_runtime=include_runtime,
|
|
145
|
+
debug=debug,
|
|
146
|
+
)
|
|
147
|
+
pair = sys.stdin.read().rstrip("\n")
|
|
148
|
+
if not pair or "=" not in pair:
|
|
149
|
+
emit_error_and_exit(
|
|
150
|
+
"Invalid argument: KEY=VALUE required",
|
|
151
|
+
code=2,
|
|
152
|
+
failure="invalid_argument",
|
|
153
|
+
command=command,
|
|
154
|
+
fmt=fmt_lower,
|
|
155
|
+
quiet=quiet,
|
|
156
|
+
include_runtime=include_runtime,
|
|
157
|
+
debug=debug,
|
|
158
|
+
)
|
|
159
|
+
raw_key, raw_value = pair.split("=", 1)
|
|
160
|
+
key = raw_key.strip()
|
|
161
|
+
service_value_str = raw_value
|
|
162
|
+
if len(service_value_str) >= 2 and (
|
|
163
|
+
(service_value_str[0] == service_value_str[-1] == '"')
|
|
164
|
+
or (service_value_str[0] == service_value_str[-1] == "'")
|
|
165
|
+
):
|
|
166
|
+
import codecs
|
|
167
|
+
|
|
168
|
+
service_value_str = codecs.decode(service_value_str[1:-1], "unicode_escape")
|
|
169
|
+
if not key:
|
|
170
|
+
emit_error_and_exit(
|
|
171
|
+
"Key cannot be empty",
|
|
172
|
+
code=2,
|
|
173
|
+
failure="empty_key",
|
|
174
|
+
command=command,
|
|
175
|
+
fmt=fmt_lower,
|
|
176
|
+
quiet=quiet,
|
|
177
|
+
include_runtime=include_runtime,
|
|
178
|
+
debug=debug,
|
|
179
|
+
)
|
|
180
|
+
if not all(ord(c) < 128 for c in key + service_value_str):
|
|
181
|
+
emit_error_and_exit(
|
|
182
|
+
"Non-ASCII characters are not allowed in keys or values.",
|
|
183
|
+
code=3,
|
|
184
|
+
failure="ascii_error",
|
|
185
|
+
command=command,
|
|
186
|
+
fmt=fmt_lower,
|
|
187
|
+
quiet=quiet,
|
|
188
|
+
include_runtime=include_runtime,
|
|
189
|
+
debug=debug,
|
|
190
|
+
extra={"key": key},
|
|
191
|
+
)
|
|
192
|
+
if not re.match(r"^[A-Za-z0-9_]+$", key):
|
|
193
|
+
emit_error_and_exit(
|
|
194
|
+
"Invalid key: only alphanumerics and underscore allowed.",
|
|
195
|
+
code=2,
|
|
196
|
+
failure="invalid_key",
|
|
197
|
+
command=command,
|
|
198
|
+
fmt=fmt_lower,
|
|
199
|
+
quiet=quiet,
|
|
200
|
+
include_runtime=include_runtime,
|
|
201
|
+
debug=debug,
|
|
202
|
+
extra={"key": key},
|
|
203
|
+
)
|
|
204
|
+
if not all(
|
|
205
|
+
c in string.printable and c not in "\r\n\t\x0b\x0c" for c in service_value_str
|
|
206
|
+
):
|
|
207
|
+
emit_error_and_exit(
|
|
208
|
+
"Control characters are not allowed in config values.",
|
|
209
|
+
code=3,
|
|
210
|
+
failure="control_char_error",
|
|
211
|
+
command=command,
|
|
212
|
+
fmt=fmt_lower,
|
|
213
|
+
quiet=quiet,
|
|
214
|
+
include_runtime=include_runtime,
|
|
215
|
+
debug=debug,
|
|
216
|
+
extra={"key": key},
|
|
217
|
+
)
|
|
218
|
+
config_svc = DIContainer.current().resolve(ConfigProtocol)
|
|
219
|
+
try:
|
|
220
|
+
config_svc.set(key, service_value_str)
|
|
221
|
+
except Exception as exc:
|
|
222
|
+
emit_error_and_exit(
|
|
223
|
+
f"Failed to set config: {exc}",
|
|
224
|
+
code=1,
|
|
225
|
+
failure="set_failed",
|
|
226
|
+
command=command,
|
|
227
|
+
fmt=fmt_lower,
|
|
228
|
+
quiet=quiet,
|
|
229
|
+
include_runtime=include_runtime,
|
|
230
|
+
debug=debug,
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def payload_builder(include_runtime: bool) -> dict[str, object]:
|
|
234
|
+
"""Builds the payload confirming a key was set or updated.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
include_runtime (bool): If True, includes Python and platform info.
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
dict[str, object]: The structured payload.
|
|
241
|
+
"""
|
|
242
|
+
payload: dict[str, object] = {
|
|
243
|
+
"status": "updated",
|
|
244
|
+
"key": key,
|
|
245
|
+
"value": service_value_str,
|
|
246
|
+
}
|
|
247
|
+
if include_runtime:
|
|
248
|
+
payload["python"] = ascii_safe(platform.python_version(), "python_version")
|
|
249
|
+
payload["platform"] = ascii_safe(platform.platform(), "platform")
|
|
250
|
+
return payload
|
|
251
|
+
|
|
252
|
+
new_run_command(
|
|
253
|
+
command_name=command,
|
|
254
|
+
payload_builder=payload_builder,
|
|
255
|
+
quiet=quiet,
|
|
256
|
+
verbose=verbose,
|
|
257
|
+
fmt=fmt_lower,
|
|
258
|
+
pretty=pretty,
|
|
259
|
+
debug=debug,
|
|
260
|
+
)
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright © 2025 Bijan Mousavi
|
|
3
|
+
|
|
4
|
+
"""Implements the `config unset` subcommand for the Bijux CLI.
|
|
5
|
+
|
|
6
|
+
This module contains the logic for removing a key-value pair from the active
|
|
7
|
+
configuration store. It provides a structured, machine-readable response to
|
|
8
|
+
confirm the deletion or report an error, such as if the key does not exist.
|
|
9
|
+
|
|
10
|
+
Output Contract:
|
|
11
|
+
* Success: `{"status": "deleted", "key": str}`
|
|
12
|
+
* Verbose: Adds `{"python": str, "platform": str}` to the payload.
|
|
13
|
+
* Error: `{"error": str, "code": int}`
|
|
14
|
+
|
|
15
|
+
Exit Codes:
|
|
16
|
+
* `0`: Success.
|
|
17
|
+
* `1`: An unexpected error occurred while accessing the configuration.
|
|
18
|
+
* `2`: The specified key was not found in the configuration.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
import platform
|
|
24
|
+
|
|
25
|
+
import typer
|
|
26
|
+
|
|
27
|
+
from bijux_cli.commands.utilities import (
|
|
28
|
+
ascii_safe,
|
|
29
|
+
emit_error_and_exit,
|
|
30
|
+
new_run_command,
|
|
31
|
+
parse_global_flags,
|
|
32
|
+
)
|
|
33
|
+
from bijux_cli.contracts import ConfigProtocol
|
|
34
|
+
from bijux_cli.core.constants import (
|
|
35
|
+
HELP_DEBUG,
|
|
36
|
+
HELP_FORMAT,
|
|
37
|
+
HELP_NO_PRETTY,
|
|
38
|
+
HELP_QUIET,
|
|
39
|
+
HELP_VERBOSE,
|
|
40
|
+
)
|
|
41
|
+
from bijux_cli.core.di import DIContainer
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def unset_config(
|
|
45
|
+
ctx: typer.Context,
|
|
46
|
+
key: str = typer.Argument(..., help="Key to remove"),
|
|
47
|
+
quiet: bool = typer.Option(False, "-q", "--quiet", help=HELP_QUIET),
|
|
48
|
+
verbose: bool = typer.Option(False, "-v", "--verbose", help=HELP_VERBOSE),
|
|
49
|
+
fmt: str = typer.Option("json", "-f", "--format", help=HELP_FORMAT),
|
|
50
|
+
pretty: bool = typer.Option(True, "--pretty/--no-pretty", help=HELP_NO_PRETTY),
|
|
51
|
+
debug: bool = typer.Option(False, "-d", "--debug", help=HELP_DEBUG),
|
|
52
|
+
) -> None:
|
|
53
|
+
"""Removes a key from the active configuration store.
|
|
54
|
+
|
|
55
|
+
This function orchestrates the `unset` operation. It manually parses global
|
|
56
|
+
flags, resolves the configuration service, attempts to remove the specified
|
|
57
|
+
key, and then uses the `new_run_command` helper to emit a structured
|
|
58
|
+
payload confirming the action.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
ctx (typer.Context): The Typer context for the CLI.
|
|
62
|
+
key (str): The configuration key to remove.
|
|
63
|
+
quiet (bool): If True, suppresses all output except for errors.
|
|
64
|
+
verbose (bool): If True, includes Python/platform details in the output.
|
|
65
|
+
fmt (str): The output format, "json" or "yaml".
|
|
66
|
+
pretty (bool): If True, pretty-prints the output.
|
|
67
|
+
debug (bool): If True, enables debug diagnostics.
|
|
68
|
+
|
|
69
|
+
Returns:
|
|
70
|
+
None:
|
|
71
|
+
|
|
72
|
+
Raises:
|
|
73
|
+
SystemExit: Always exits with a contract-compliant status code and
|
|
74
|
+
payload, indicating success or detailing the error.
|
|
75
|
+
"""
|
|
76
|
+
flags = parse_global_flags()
|
|
77
|
+
|
|
78
|
+
quiet = flags["quiet"]
|
|
79
|
+
verbose = flags["verbose"]
|
|
80
|
+
fmt = flags["format"]
|
|
81
|
+
pretty = flags["pretty"]
|
|
82
|
+
debug = flags["debug"]
|
|
83
|
+
|
|
84
|
+
include_runtime = verbose
|
|
85
|
+
fmt_lower = fmt.lower()
|
|
86
|
+
|
|
87
|
+
command = "config unset"
|
|
88
|
+
|
|
89
|
+
config_svc = DIContainer.current().resolve(ConfigProtocol)
|
|
90
|
+
|
|
91
|
+
try:
|
|
92
|
+
config_svc.unset(key)
|
|
93
|
+
except KeyError:
|
|
94
|
+
emit_error_and_exit(
|
|
95
|
+
f"Config key not found: {key}",
|
|
96
|
+
code=2,
|
|
97
|
+
failure="not_found",
|
|
98
|
+
command=command,
|
|
99
|
+
fmt=fmt_lower,
|
|
100
|
+
quiet=quiet,
|
|
101
|
+
include_runtime=include_runtime,
|
|
102
|
+
debug=debug,
|
|
103
|
+
extra={"key": key},
|
|
104
|
+
)
|
|
105
|
+
except Exception as exc:
|
|
106
|
+
emit_error_and_exit(
|
|
107
|
+
f"Failed to unset config: {exc}",
|
|
108
|
+
code=1,
|
|
109
|
+
failure="unset_failed",
|
|
110
|
+
command=command,
|
|
111
|
+
fmt=fmt_lower,
|
|
112
|
+
quiet=quiet,
|
|
113
|
+
include_runtime=include_runtime,
|
|
114
|
+
debug=debug,
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def payload_builder(include_runtime: bool) -> dict[str, object]:
|
|
118
|
+
"""Builds the payload confirming a key was deleted.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
include_runtime (bool): If True, includes Python and platform info.
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
dict[str, object]: The structured payload.
|
|
125
|
+
"""
|
|
126
|
+
payload: dict[str, object] = {"status": "deleted", "key": key}
|
|
127
|
+
if include_runtime:
|
|
128
|
+
payload["python"] = ascii_safe(platform.python_version(), "python_version")
|
|
129
|
+
payload["platform"] = ascii_safe(platform.platform(), "platform")
|
|
130
|
+
return payload
|
|
131
|
+
|
|
132
|
+
new_run_command(
|
|
133
|
+
command_name=command,
|
|
134
|
+
payload_builder=payload_builder,
|
|
135
|
+
quiet=quiet,
|
|
136
|
+
verbose=verbose,
|
|
137
|
+
fmt=fmt_lower,
|
|
138
|
+
pretty=pretty,
|
|
139
|
+
debug=debug,
|
|
140
|
+
)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
# Copyright © 2025 Bijan Mousavi
|
|
3
|
+
|
|
4
|
+
"""Defines the `dev` command group for the Bijux CLI.
|
|
5
|
+
|
|
6
|
+
This module serves as the central entry point for all developer-focused tools
|
|
7
|
+
and diagnostics. It aggregates the various subcommands into a single `Typer`
|
|
8
|
+
application, creating the `bijux dev` command hierarchy.
|
|
9
|
+
|
|
10
|
+
The `dev` command, when run without a subcommand, provides a simple status
|
|
11
|
+
confirmation.
|
|
12
|
+
|
|
13
|
+
The available subcommands are:
|
|
14
|
+
* `di`: Displays the dependency injection (DI) container graph.
|
|
15
|
+
* `list-plugins`: Lists all installed CLI plugins.
|
|
16
|
+
|
|
17
|
+
Exit codes for the subcommands generally follow this pattern:
|
|
18
|
+
* `0`: Success.
|
|
19
|
+
* `1`: An internal or unexpected error occurred.
|
|
20
|
+
* `2`: An invalid argument was provided (e.g., bad format).
|
|
21
|
+
* `3`: An ASCII or encoding error was detected.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
import typer
|
|
27
|
+
|
|
28
|
+
from bijux_cli.commands.dev.di import dev_di_graph
|
|
29
|
+
from bijux_cli.commands.dev.list_plugins import dev_list_plugins
|
|
30
|
+
from bijux_cli.commands.dev.service import dev
|
|
31
|
+
|
|
32
|
+
typer.core.rich = None # type: ignore[attr-defined,assignment]
|
|
33
|
+
|
|
34
|
+
dev_app = typer.Typer( # pytype: skip-file
|
|
35
|
+
name="dev",
|
|
36
|
+
help="Developer tools and diagnostics.",
|
|
37
|
+
rich_markup_mode=None,
|
|
38
|
+
context_settings={"help_option_names": ["-h", "--help"]},
|
|
39
|
+
no_args_is_help=False,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
dev_app.callback(invoke_without_command=True)(dev)
|
|
43
|
+
dev_app.command("di")(dev_di_graph)
|
|
44
|
+
dev_app.command("list-plugins")(dev_list_plugins)
|
|
45
|
+
|
|
46
|
+
__all__ = ["dev_app"]
|