botgauge-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.
- botgauge/cli/__init__.py +42 -0
- botgauge/cli/__main__.py +6 -0
- botgauge/cli/_dispatch.py +241 -0
- botgauge/cli/_names.py +78 -0
- botgauge_cli-0.1.0.dist-info/METADATA +38 -0
- botgauge_cli-0.1.0.dist-info/RECORD +10 -0
- botgauge_cli-0.1.0.dist-info/WHEEL +5 -0
- botgauge_cli-0.1.0.dist-info/entry_points.txt +3 -0
- botgauge_cli-0.1.0.dist-info/licenses/LICENSE +105 -0
- botgauge_cli-0.1.0.dist-info/top_level.txt +1 -0
botgauge/cli/__init__.py
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""The ``botgauge`` command.
|
|
2
|
+
|
|
3
|
+
Owns the ``botgauge`` console script and its short alias, and dispatches each command to the
|
|
4
|
+
installed BotGauge component that registers it in the ``botgauge.commands`` entry-point group.
|
|
5
|
+
Standard library only.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from ._dispatch import main
|
|
10
|
+
from ._names import ENTRY_POINT_GROUP, RESERVED, command_names
|
|
11
|
+
|
|
12
|
+
#: Read from the installed metadata on first access (see ``__getattr__``); declared here for type checkers.
|
|
13
|
+
__version__: str
|
|
14
|
+
__all__ = ["ENTRY_POINT_GROUP", "RESERVED", "__version__", "command_names", "main"]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def __getattr__(name: str) -> str:
|
|
18
|
+
"""Resolve ``__version__`` lazily from the installed distribution metadata.
|
|
19
|
+
|
|
20
|
+
The value is cached in the module globals after the first lookup.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
name: The attribute being looked up on the module.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
The installed ``botgauge-cli`` version, or ``"0+unknown"`` when it is not installed.
|
|
27
|
+
|
|
28
|
+
Raises:
|
|
29
|
+
AttributeError: ``name`` is not ``__version__``.
|
|
30
|
+
"""
|
|
31
|
+
# The version is defined once, in pyproject.toml, and read from the installed metadata the first
|
|
32
|
+
# time something asks for it. A source tree that was never installed reports "0+unknown".
|
|
33
|
+
if name == "__version__":
|
|
34
|
+
from importlib import metadata
|
|
35
|
+
|
|
36
|
+
try:
|
|
37
|
+
version = metadata.version("botgauge-cli")
|
|
38
|
+
except metadata.PackageNotFoundError:
|
|
39
|
+
version = "0+unknown"
|
|
40
|
+
globals()["__version__"] = version
|
|
41
|
+
return version
|
|
42
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
botgauge/cli/__main__.py
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
"""Dispatch ``botgauge <command>`` to the component that owns it.
|
|
2
|
+
|
|
3
|
+
Components register commands in the ``botgauge.commands`` entry-point group; this module only finds
|
|
4
|
+
and runs them. Rules, so a command never silently changes meaning:
|
|
5
|
+
|
|
6
|
+
* a reserved name (``_names.RESERVED``) runs only from its owner; another distribution registering it
|
|
7
|
+
is ignored and reported by ``--help``;
|
|
8
|
+
* a reserved name is resolved from the owner's metadata alone, never a scan of every installed
|
|
9
|
+
distribution, so ``botgauge instrument`` (which execs the application) stays cheap;
|
|
10
|
+
* an unreserved name registered twice is refused, naming every registering distribution; nothing
|
|
11
|
+
wins silently;
|
|
12
|
+
* a command whose owner is not installed says which distribution provides it;
|
|
13
|
+
* a component that fails to import fails only its own command, with a message naming it.
|
|
14
|
+
|
|
15
|
+
Exit codes: the command's own; 0 for help/version; 2 for usage errors (no, unknown, ambiguous,
|
|
16
|
+
unavailable or unloadable command).
|
|
17
|
+
"""
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import os
|
|
21
|
+
import sys
|
|
22
|
+
from importlib import metadata
|
|
23
|
+
|
|
24
|
+
from ._names import (
|
|
25
|
+
BUILTINS,
|
|
26
|
+
DISTRIBUTION,
|
|
27
|
+
ENTRY_POINT_GROUP,
|
|
28
|
+
PLATFORM,
|
|
29
|
+
RESERVED,
|
|
30
|
+
command_names,
|
|
31
|
+
install_hint,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
_USAGE = "usage: {prog} <command> [args] ({prog} help for every installed command)\n"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _prog() -> str:
|
|
38
|
+
"""Return the console-script name the user invoked, or ``botgauge`` if it is not one of ours."""
|
|
39
|
+
invoked = os.path.basename(sys.argv[0] or "")
|
|
40
|
+
invoked = invoked[:-4] if invoked.lower().endswith(".exe") else invoked
|
|
41
|
+
return invoked if invoked in command_names() else "botgauge"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _distribution(ep: metadata.EntryPoint) -> str:
|
|
45
|
+
"""Return the name of the distribution that registered ``ep``, or a placeholder if unknown."""
|
|
46
|
+
return getattr(getattr(ep, "dist", None), "name", None) or "<unknown distribution>"
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _all_command_entry_points() -> dict[str, list[metadata.EntryPoint]]:
|
|
50
|
+
"""Scan every installed distribution and group its ``botgauge.commands`` entry points by name."""
|
|
51
|
+
found: dict[str, list[metadata.EntryPoint]] = {}
|
|
52
|
+
for ep in metadata.entry_points(group=ENTRY_POINT_GROUP):
|
|
53
|
+
found.setdefault(ep.name, []).append(ep)
|
|
54
|
+
return found
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def _owner_entry_point(name: str, owner: str) -> tuple[metadata.EntryPoint | None, str]:
|
|
58
|
+
"""Find the owner's entry point for a reserved name, reading only the owner's metadata.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
name: The reserved command name.
|
|
62
|
+
owner: The distribution that must provide ``name``.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
``(entry_point, "")`` on success, or ``(None, problem)`` when the owner is not installed or
|
|
66
|
+
does not register ``name``.
|
|
67
|
+
"""
|
|
68
|
+
try:
|
|
69
|
+
dist = metadata.distribution(owner)
|
|
70
|
+
except metadata.PackageNotFoundError:
|
|
71
|
+
return None, f"'{name}' is provided by {owner}, which is not installed ({install_hint(owner)})"
|
|
72
|
+
for ep in dist.entry_points:
|
|
73
|
+
if ep.group == ENTRY_POINT_GROUP and ep.name == name:
|
|
74
|
+
return ep, ""
|
|
75
|
+
return None, f"{owner} is installed but does not register '{name}' (a version mismatch?)"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def _resolve(name: str) -> tuple[metadata.EntryPoint | None, str]:
|
|
79
|
+
"""Resolve a command name to the single entry point allowed to run it.
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
name: The command name typed after ``botgauge``.
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
``(entry_point, "")`` on success, or ``(None, problem)`` for an unknown, ambiguous or
|
|
86
|
+
unavailable command.
|
|
87
|
+
"""
|
|
88
|
+
if name in RESERVED:
|
|
89
|
+
return _owner_entry_point(name, RESERVED[name])
|
|
90
|
+
candidates = _all_command_entry_points().get(name, [])
|
|
91
|
+
if not candidates:
|
|
92
|
+
return None, f"unknown command '{name}'"
|
|
93
|
+
if len(candidates) > 1:
|
|
94
|
+
owners = ", ".join(sorted(_distribution(ep) for ep in candidates))
|
|
95
|
+
return None, f"'{name}' is registered by more than one package ({owners}); refusing to guess"
|
|
96
|
+
return candidates[0], ""
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def _run(name: str, rest: list[str], prog: str) -> int:
|
|
100
|
+
"""Load and run one command, reporting resolution and import failures on stderr.
|
|
101
|
+
|
|
102
|
+
Args:
|
|
103
|
+
name: The command name.
|
|
104
|
+
rest: Arguments passed to the command's handler.
|
|
105
|
+
prog: The invoked program name, used in error messages.
|
|
106
|
+
|
|
107
|
+
Returns:
|
|
108
|
+
The handler's return value as an int (``None`` counts as 0), or 2 if the command could not be
|
|
109
|
+
resolved or loaded.
|
|
110
|
+
"""
|
|
111
|
+
ep, problem = _resolve(name)
|
|
112
|
+
if ep is None:
|
|
113
|
+
print(f"{prog}: {problem}", file=sys.stderr)
|
|
114
|
+
print(f"Run '{prog} help' to list the installed commands.", file=sys.stderr)
|
|
115
|
+
return 2
|
|
116
|
+
try:
|
|
117
|
+
handler = ep.load()
|
|
118
|
+
except Exception as exc: # noqa: BLE001 - a broken component must not take the whole CLI down
|
|
119
|
+
print(f"{prog}: the '{name}' command (from {_distribution(ep)}) could not be loaded: "
|
|
120
|
+
f"{type(exc).__name__}: {exc}", file=sys.stderr)
|
|
121
|
+
return 2
|
|
122
|
+
result = handler(rest)
|
|
123
|
+
return int(result) if result is not None else 0
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _summary(ep: metadata.EntryPoint) -> str:
|
|
127
|
+
"""Return the first line of the handler's docstring for ``help``; this imports the component.
|
|
128
|
+
|
|
129
|
+
For a command that ``help`` lists, the handler's docstring is therefore user-visible help
|
|
130
|
+
text: changing its first line changes the ``botgauge help`` output. (An unreserved name
|
|
131
|
+
registered more than once is not listed, and neither is a reserved name registered only by a
|
|
132
|
+
non-owner; a reserved name is listed from its owner's entry even when other distributions
|
|
133
|
+
also register it.)
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
ep: Entry point of the command whose summary is wanted.
|
|
137
|
+
|
|
138
|
+
Returns:
|
|
139
|
+
The summary line; an empty string for a handler without a docstring, or
|
|
140
|
+
``(could not be loaded: <type>)`` when the component fails to import.
|
|
141
|
+
"""
|
|
142
|
+
try:
|
|
143
|
+
doc = ep.load().__doc__ or ""
|
|
144
|
+
except Exception as exc: # noqa: BLE001 - list it as unavailable, keep listing the rest
|
|
145
|
+
return f"(could not be loaded: {type(exc).__name__})"
|
|
146
|
+
return doc.strip().splitlines()[0] if doc.strip() else ""
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
def _print_help(prog: str) -> None:
|
|
150
|
+
"""Print every installed command by section, the reserved commands not installed, and ignored registrations."""
|
|
151
|
+
others = [n for n in command_names() if n != prog]
|
|
152
|
+
alias = f" (also: {', '.join(others)})" if others else ""
|
|
153
|
+
print(_USAGE.format(prog=prog).rstrip("\n") + alias)
|
|
154
|
+
found = _all_command_entry_points()
|
|
155
|
+
rows: dict[str, list[tuple[str, str, str]]] = {"Platform": [], "Groups": [], "Other": []}
|
|
156
|
+
ignored: list[str] = []
|
|
157
|
+
for name in BUILTINS:
|
|
158
|
+
rows["Platform"].append((name, "this help" if name == "help" else "installed versions", DISTRIBUTION))
|
|
159
|
+
for name, eps in sorted(found.items()):
|
|
160
|
+
owner = RESERVED.get(name)
|
|
161
|
+
if owner is not None:
|
|
162
|
+
ignored += [f"{_distribution(ep)} registers '{name}', which is reserved for {owner}"
|
|
163
|
+
for ep in eps if _distribution(ep) != owner]
|
|
164
|
+
eps = [ep for ep in eps if _distribution(ep) == owner]
|
|
165
|
+
if not eps:
|
|
166
|
+
continue
|
|
167
|
+
section = "Platform" if name in PLATFORM else "Groups"
|
|
168
|
+
elif len(eps) > 1:
|
|
169
|
+
owners = ", ".join(sorted(_distribution(ep) for ep in eps))
|
|
170
|
+
ignored.append(f"'{name}' is registered by {owners}; refused")
|
|
171
|
+
continue
|
|
172
|
+
else:
|
|
173
|
+
section = "Other"
|
|
174
|
+
rows[section].append((name, _summary(eps[0]), _distribution(eps[0])))
|
|
175
|
+
titles = {"Platform": "Commands", "Groups": f"Groups ({prog} <group> <verb>; {prog} <group> --help)",
|
|
176
|
+
"Other": "Other installed commands"}
|
|
177
|
+
for section, entries in rows.items():
|
|
178
|
+
if entries:
|
|
179
|
+
print(f"\n{titles[section]}:")
|
|
180
|
+
for name, summary, dist in entries:
|
|
181
|
+
print(f" {name:<12} {summary} [{dist}]")
|
|
182
|
+
installed = {name for name, eps in found.items() for ep in eps if _distribution(ep) == RESERVED.get(name)}
|
|
183
|
+
missing: dict[str, list[str]] = {}
|
|
184
|
+
for name, owner in RESERVED.items():
|
|
185
|
+
if name not in installed:
|
|
186
|
+
missing.setdefault(owner, []).append(name)
|
|
187
|
+
if missing:
|
|
188
|
+
print("\nNot installed:")
|
|
189
|
+
for owner, cmds in sorted(missing.items()):
|
|
190
|
+
print(f" {', '.join(cmds):<40} {install_hint(owner)}")
|
|
191
|
+
for line in ignored:
|
|
192
|
+
print(f"\nignored: {line}")
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _print_version() -> None:
|
|
196
|
+
"""Print this distribution's version and that of every distribution registering a command."""
|
|
197
|
+
try:
|
|
198
|
+
own = metadata.version(DISTRIBUTION)
|
|
199
|
+
except metadata.PackageNotFoundError:
|
|
200
|
+
own = "(not installed)"
|
|
201
|
+
print(f"{DISTRIBUTION} {own}")
|
|
202
|
+
dists = sorted({_distribution(ep) for eps in _all_command_entry_points().values() for ep in eps})
|
|
203
|
+
for dist in dists:
|
|
204
|
+
try:
|
|
205
|
+
print(f" {dist} {metadata.version(dist)}")
|
|
206
|
+
except metadata.PackageNotFoundError:
|
|
207
|
+
print(f" {dist}")
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def main(argv: list[str] | None = None) -> int:
|
|
211
|
+
"""Dispatch one ``botgauge`` command.
|
|
212
|
+
|
|
213
|
+
Args:
|
|
214
|
+
argv: Command arguments, or None to use ``sys.argv[1:]``.
|
|
215
|
+
|
|
216
|
+
Returns:
|
|
217
|
+
The command's exit code (``help <command>`` returns that command's exit code for
|
|
218
|
+
``--help``); 0 for help/version; 2 for a missing, unknown, ambiguous, uninstalled or
|
|
219
|
+
unloadable command. ``help`` followed by a built-in name (``help`` or ``version``) is
|
|
220
|
+
looked up like any other command name: it is an unknown command (2) unless a plugin
|
|
221
|
+
registers that name, in which case the plugin runs with ``--help``.
|
|
222
|
+
|
|
223
|
+
Raises:
|
|
224
|
+
SystemExit: A command's argument parser exits for help or invalid options.
|
|
225
|
+
Exception: Any other exception raised by a command handler propagates unchanged.
|
|
226
|
+
"""
|
|
227
|
+
args = sys.argv[1:] if argv is None else list(argv)
|
|
228
|
+
prog = _prog()
|
|
229
|
+
if not args:
|
|
230
|
+
print(_USAGE.format(prog=prog), end="")
|
|
231
|
+
return 2
|
|
232
|
+
first, rest = args[0], args[1:]
|
|
233
|
+
if first in ("-h", "--help", "help"):
|
|
234
|
+
if first == "help" and rest:
|
|
235
|
+
return _run(rest[0], ["--help"], prog)
|
|
236
|
+
_print_help(prog)
|
|
237
|
+
return 0
|
|
238
|
+
if first in ("-V", "--version", "version"):
|
|
239
|
+
_print_version()
|
|
240
|
+
return 0
|
|
241
|
+
return _run(first, rest, prog)
|
botgauge/cli/_names.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Who owns which ``botgauge`` command.
|
|
2
|
+
|
|
3
|
+
Every top-level name a BotGauge distribution may register is listed here with its owner. The
|
|
4
|
+
dispatcher runs a reserved name only from its owner, so another package can never take over
|
|
5
|
+
``botgauge instrument``, and resolving a reserved name reads only the owner's
|
|
6
|
+
metadata instead of scanning every installed distribution (``botgauge instrument`` stays cheap).
|
|
7
|
+
Third-party plugins may register other names; they never shadow these.
|
|
8
|
+
|
|
9
|
+
Adding a component's command is a reviewed change to this file, released with that component
|
|
10
|
+
(lockstep versions). A BotGauge distribution must not register a name that is not reserved for it
|
|
11
|
+
here.
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
from importlib import metadata
|
|
16
|
+
|
|
17
|
+
#: The entry-point group every component registers its commands under: ``name = "pkg.mod:fn"``,
|
|
18
|
+
#: where ``fn(argv: list[str]) -> int``.
|
|
19
|
+
ENTRY_POINT_GROUP = "botgauge.commands"
|
|
20
|
+
|
|
21
|
+
#: This distribution; its console scripts are the command names.
|
|
22
|
+
DISTRIBUTION = "botgauge-cli"
|
|
23
|
+
|
|
24
|
+
#: Built into the dispatcher itself.
|
|
25
|
+
BUILTINS = ("help", "version")
|
|
26
|
+
|
|
27
|
+
#: Platform verbs stay top-level; every other name is a noun group: ``botgauge <noun> <verb>``.
|
|
28
|
+
PLATFORM = ("instrument", "probe", "doctor", "setup", *BUILTINS)
|
|
29
|
+
|
|
30
|
+
#: name -> the distribution that must provide it.
|
|
31
|
+
RESERVED: dict[str, str] = {
|
|
32
|
+
"instrument": "botgauge-tracing",
|
|
33
|
+
"probe": "botgauge-tracing",
|
|
34
|
+
"doctor": "botgauge-tracing",
|
|
35
|
+
"setup": "botgauge-tracing",
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
#: Distributions published on PyPI. Only these get a `pip install` hint: an unpublished name is
|
|
39
|
+
#: either a 404 or, once someone else registers it, a third party's code. Add a distribution here in
|
|
40
|
+
#: the release that first publishes it.
|
|
41
|
+
PUBLISHED = frozenset({"botgauge", "botgauge-cli", "botgauge-tracing"})
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def install_hint(owner: str) -> str:
|
|
45
|
+
"""Return how to install ``owner``'s commands.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
owner: A distribution name.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
``"pip install <owner>"`` for a published distribution, otherwise a note that this release
|
|
52
|
+
does not publish it.
|
|
53
|
+
"""
|
|
54
|
+
return f"pip install {owner}" if owner in PUBLISHED else "not published in this release"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
_PRIMARY = "botgauge"
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def command_names() -> tuple[str, ...]:
|
|
61
|
+
"""Return the installed console-script names for this dispatcher, ``botgauge`` first.
|
|
62
|
+
|
|
63
|
+
Read from this distribution's own metadata, so the short alias is defined once, in
|
|
64
|
+
``pyproject.toml``.
|
|
65
|
+
|
|
66
|
+
Returns:
|
|
67
|
+
``botgauge`` followed by every other console script of ``botgauge-cli``, or
|
|
68
|
+
``("botgauge",)`` when the metadata is unavailable (a source checkout run without
|
|
69
|
+
installing) or declares no console scripts.
|
|
70
|
+
"""
|
|
71
|
+
try:
|
|
72
|
+
eps = metadata.distribution(DISTRIBUTION).entry_points
|
|
73
|
+
except metadata.PackageNotFoundError:
|
|
74
|
+
return (_PRIMARY,)
|
|
75
|
+
# Every console script of this distribution, whatever it points at: a script aimed at the wrong
|
|
76
|
+
# function must show up here (and fail the release gates), not silently drop out.
|
|
77
|
+
names = sorted(ep.name for ep in eps if ep.group == "console_scripts")
|
|
78
|
+
return (_PRIMARY, *(n for n in names if n != _PRIMARY)) if names else (_PRIMARY,)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: botgauge-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: The `botgauge` command: one entry point that dispatches to every installed BotGauge component.
|
|
5
|
+
Author-email: "BotGauge AI Inc." <support@botgauge.com>
|
|
6
|
+
License-Expression: FSL-1.1-ALv2
|
|
7
|
+
Project-URL: Homepage, https://www.botgauge.com/
|
|
8
|
+
Keywords: botgauge,cli
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Dynamic: license-file
|
|
22
|
+
|
|
23
|
+
# botgauge-cli
|
|
24
|
+
|
|
25
|
+
The `botgauge` command. It owns the `botgauge` console script (plus a short alias, `botg`) and
|
|
26
|
+
dispatches each command to the installed BotGauge component that provides it:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
botgauge help # every installed command, and which package provides the rest
|
|
30
|
+
botgauge version # installed BotGauge versions
|
|
31
|
+
botgauge instrument python app.py # provided by botgauge-tracing
|
|
32
|
+
botgauge doctor # provided by botgauge-tracing
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Components register commands in the `botgauge.commands` entry-point group. Top-level names are
|
|
36
|
+
reserved per package (`src/botgauge/cli/_names.py`), so one package can never take over another's
|
|
37
|
+
command. Standard library only; every BotGauge component depends on it. You normally get it through
|
|
38
|
+
`pip install botgauge` rather than installing it directly.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
botgauge/cli/__init__.py,sha256=a4_oVNm2VKBQaHuNDQQ05C-6hHqt_4PdoONlvba9KHU,1579
|
|
2
|
+
botgauge/cli/__main__.py,sha256=YgvCeaA_NXPq8B-R_ArNqlOVse0w-12As4qjSIOJj1w,143
|
|
3
|
+
botgauge/cli/_dispatch.py,sha256=A4-y1ePaihfHD8v4v_TaGWrG0I3trduXtUeFbyN6TFU,10161
|
|
4
|
+
botgauge/cli/_names.py,sha256=rIO6hlZDDzUOAJGbEon-38ZzeQRsCNOAgaOK_wcFrX0,3160
|
|
5
|
+
botgauge_cli-0.1.0.dist-info/licenses/LICENSE,sha256=EplDjGiYxLsggvWIv03TjBXk_gABXU88NMWtl_T26cU,3748
|
|
6
|
+
botgauge_cli-0.1.0.dist-info/METADATA,sha256=ByNii7uEBR8P3-wxANjkUSdunVFboicEycJPopHnkhU,1697
|
|
7
|
+
botgauge_cli-0.1.0.dist-info/WHEEL,sha256=a-udL2m4V_6Yn8b-uKzWb12RjRxwwMo6ohYFM24tpaY,91
|
|
8
|
+
botgauge_cli-0.1.0.dist-info/entry_points.txt,sha256=GiQBZ1kSGAPZa2GRMJgJVlSuxpOpChYhteLBtRR9xK0,72
|
|
9
|
+
botgauge_cli-0.1.0.dist-info/top_level.txt,sha256=qr2kZrd0gkelTuQTeCyA68V8ewK04QkEynqd-So9t88,9
|
|
10
|
+
botgauge_cli-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Functional Source License, Version 1.1, ALv2 Future License
|
|
2
|
+
|
|
3
|
+
## Abbreviation
|
|
4
|
+
|
|
5
|
+
FSL-1.1-ALv2
|
|
6
|
+
|
|
7
|
+
## Notice
|
|
8
|
+
|
|
9
|
+
Copyright 2026 BotGauge AI Inc.
|
|
10
|
+
|
|
11
|
+
## Terms and Conditions
|
|
12
|
+
|
|
13
|
+
### Licensor ("We")
|
|
14
|
+
|
|
15
|
+
The party offering the Software under these Terms and Conditions.
|
|
16
|
+
|
|
17
|
+
### The Software
|
|
18
|
+
|
|
19
|
+
The "Software" is each version of the software that we make available under
|
|
20
|
+
these Terms and Conditions, as indicated by our inclusion of these Terms and
|
|
21
|
+
Conditions with the Software.
|
|
22
|
+
|
|
23
|
+
### License Grant
|
|
24
|
+
|
|
25
|
+
Subject to your compliance with this License Grant and the Patents,
|
|
26
|
+
Redistribution and Trademark clauses below, we hereby grant you the right to
|
|
27
|
+
use, copy, modify, create derivative works, publicly perform, publicly display
|
|
28
|
+
and redistribute the Software for any Permitted Purpose identified below.
|
|
29
|
+
|
|
30
|
+
### Permitted Purpose
|
|
31
|
+
|
|
32
|
+
A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
|
|
33
|
+
means making the Software available to others in a commercial product or
|
|
34
|
+
service that:
|
|
35
|
+
|
|
36
|
+
1. substitutes for the Software;
|
|
37
|
+
|
|
38
|
+
2. substitutes for any other product or service we offer using the Software
|
|
39
|
+
that exists as of the date we make the Software available; or
|
|
40
|
+
|
|
41
|
+
3. offers the same or substantially similar functionality as the Software.
|
|
42
|
+
|
|
43
|
+
Permitted Purposes specifically include using the Software:
|
|
44
|
+
|
|
45
|
+
1. for your internal use and access;
|
|
46
|
+
|
|
47
|
+
2. for non-commercial education;
|
|
48
|
+
|
|
49
|
+
3. for non-commercial research; and
|
|
50
|
+
|
|
51
|
+
4. in connection with professional services that you provide to a licensee
|
|
52
|
+
using the Software in accordance with these Terms and Conditions.
|
|
53
|
+
|
|
54
|
+
### Patents
|
|
55
|
+
|
|
56
|
+
To the extent your use for a Permitted Purpose would necessarily infringe our
|
|
57
|
+
patents, the license grant above includes a license under our patents. If you
|
|
58
|
+
make a claim against any party that the Software infringes or contributes to
|
|
59
|
+
the infringement of any patent, then your patent license to the Software ends
|
|
60
|
+
immediately.
|
|
61
|
+
|
|
62
|
+
### Redistribution
|
|
63
|
+
|
|
64
|
+
The Terms and Conditions apply to all copies, modifications and derivatives of
|
|
65
|
+
the Software.
|
|
66
|
+
|
|
67
|
+
If you redistribute any copies, modifications or derivatives of the Software,
|
|
68
|
+
you must include a copy of or a link to these Terms and Conditions and not
|
|
69
|
+
remove any copyright notices provided in or with the Software.
|
|
70
|
+
|
|
71
|
+
### Disclaimer
|
|
72
|
+
|
|
73
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
|
|
74
|
+
IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
|
|
75
|
+
PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
|
|
76
|
+
|
|
77
|
+
IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
|
|
78
|
+
SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
|
|
79
|
+
EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
|
|
80
|
+
|
|
81
|
+
### Trademarks
|
|
82
|
+
|
|
83
|
+
Except for displaying the License Details and identifying us as the origin of
|
|
84
|
+
the Software, you have no right under these Terms and Conditions to use our
|
|
85
|
+
trademarks, trade names, service marks or product names.
|
|
86
|
+
|
|
87
|
+
## Grant of Future License
|
|
88
|
+
|
|
89
|
+
We hereby irrevocably grant you an additional license to use the Software under
|
|
90
|
+
the Apache License, Version 2.0 that is effective on the second anniversary of
|
|
91
|
+
the date we make the Software available. On or after that date, you may use the
|
|
92
|
+
Software under the Apache License, Version 2.0, in which case the following
|
|
93
|
+
will apply:
|
|
94
|
+
|
|
95
|
+
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
|
96
|
+
this file except in compliance with the License.
|
|
97
|
+
|
|
98
|
+
You may obtain a copy of the License at
|
|
99
|
+
|
|
100
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
101
|
+
|
|
102
|
+
Unless required by applicable law or agreed to in writing, software distributed
|
|
103
|
+
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
|
|
104
|
+
CONDITIONS OF ANY KIND, either express or implied. See the License for the
|
|
105
|
+
specific language governing permissions and limitations under the License.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
botgauge
|