chore: rename project coven → hack-house ⛧

Rebrand the Rust client crate (coven/ → hh/, package+binary "hack-house"),
README, CLI strings, and branch (coven → hack-house). Gitea repo renamed
cmd-chat → hack-house to match. Crypto/server logic unchanged; selftest +
golden-vector test still green, binary is now `hack-house`.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
leetcrypt
2026-05-30 13:29:14 -07:00
parent 82a04f3e12
commit bb1d662ee1
2730 changed files with 712933 additions and 46 deletions
@@ -0,0 +1,13 @@
from sanic import Request
from sanic.exceptions import SanicException
def extract_request(*args) -> Request:
request: Request
if args and isinstance(args[0], Request):
request = args[0]
elif len(args) > 1:
request = args[1]
else:
raise SanicException("Request could not be found")
return request
@@ -0,0 +1,124 @@
import re
def clean_route_name(name: str) -> str:
parts = name.split(".", 1)
name = parts[-1]
for target in ("_", ".", " "):
name = name.replace(target, " ")
return name.title()
def get_uri_filter(app):
"""
Return a filter function that takes a URI and returns whether it should
be filter out from the swagger documentation or not.
Arguments:
app: The application to take `config.API_URI_FILTER` from. Possible
values for this config option are: `slash` (to keep URIs that
end with a `/`), `all` (to keep all URIs). All other values
default to keep all URIs that don't end with a `/`.
Returns:
`True` if the URI should be *filtered out* from the swagger
documentation, and `False` if it should be kept in the documentation.
"""
choice = getattr(app.config, "API_URI_FILTER", None)
if choice == "slash":
# Keep URIs that end with a /.
return lambda uri: not uri.endswith("/")
if choice == "all":
# Keep all URIs.
return lambda uri: False
# Keep URIs that don't end with a /, (special case: "/").
return lambda uri: len(uri) > 1 and uri.endswith("/")
def remove_nulls(dictionary, deep=True):
"""
Removes all null values from a dictionary.
"""
return {
k: remove_nulls(v, deep) if deep and isinstance(v, dict) else v
for k, v in dictionary.items()
if v is not None
}
def remove_nulls_from_kwargs(**kwargs):
return remove_nulls(kwargs, deep=False)
def get_blueprinted_routes(app):
for blueprint in app.blueprints.values():
if not hasattr(blueprint, "routes"):
continue
for route in blueprint.routes:
if hasattr(route.handler, "view_class"):
# before sanic 21.3, route.handler could be a number of
# different things, so have to type check
for http_method in route.methods:
_handler = getattr(
route.handler.view_class, http_method.lower(), None
)
if _handler:
yield (blueprint.name, _handler)
else:
yield (blueprint.name, route.handler)
def get_all_routes(app, skip_prefix):
uri_filter = get_uri_filter(app)
for group in app.router.groups.values():
uri = f"/{group.path}"
# prior to sanic 21.3 routes came in both forms
# (e.g. /test and /test/ )
# after sanic 21.3 routes come in one form,
# with an attribute "strict",
# so we simulate that ourselves:
uris = [uri]
if not group.strict and len(uri) > 1:
alt = uri[:-1] if uri.endswith("/") else f"{uri}/"
uris.append(alt)
for uri in uris:
if uri_filter(uri):
continue
if skip_prefix and group.raw_path.startswith(
skip_prefix.lstrip("/")
):
continue
for parameter in group.params.values():
uri = re.sub(
f"<{parameter.name}.*?>",
f"{{{parameter.name}}}",
uri,
)
for route in group:
if getattr(route.extra, "static", False):
continue
method_handlers = [
(method, route.handler) for method in route.methods
]
_, name = route.name.split(".", 1)
yield (
uri,
name,
route.params.values(),
method_handlers,
route.requirements.get("host"),
)
@@ -0,0 +1,13 @@
import re
CAMEL_TO_SNAKE_PATTERNS = (
re.compile(r"(.)([A-Z][a-z]+)"),
re.compile(r"([a-z0-9])([A-Z])"),
)
def camel_to_snake(name: str) -> str:
for pattern in CAMEL_TO_SNAKE_PATTERNS:
name = pattern.sub(r"\1_\2", name)
return name.lower()
@@ -0,0 +1,79 @@
import types
import typing
from inspect import isclass
try:
UnionType = types.UnionType # type: ignore
except AttributeError:
UnionType = type("UnionType", (), {}) # type: ignore
try:
from pydantic import BaseModel
PYDANTIC = True
except ImportError:
PYDANTIC = False
try:
import attrs # noqa
ATTRS = True
except ImportError:
ATTRS = False
try:
from msgspec import Struct
MSGSPEC = True
except ImportError:
MSGSPEC = False
def is_generic(item):
return (
isinstance(item, typing._GenericAlias)
or isinstance(item, UnionType)
or hasattr(item, "__origin__")
)
def is_optional(item):
if is_generic(item):
args = typing.get_args(item)
return len(args) == 2 and type(None) in args
return False
def is_pydantic(model):
return PYDANTIC and (
issubclass(model, BaseModel) or hasattr(model, "__pydantic_model__")
)
def is_attrs(model):
return ATTRS and (hasattr(model, "__attrs_attrs__"))
def is_msgspec(model):
return MSGSPEC and issubclass(model, Struct)
def flat_values(
item: typing.Union[dict[str, typing.Any], typing.Iterable[typing.Any]],
) -> set[typing.Any]:
values = set()
if isinstance(item, dict):
item = item.values()
for value in item:
if isinstance(value, dict) or isinstance(value, list):
values.update(flat_values(value))
else:
values.add(value)
return values
def contains_annotations(d: dict[str, typing.Any]) -> bool:
values = flat_values(d)
return any(isclass(q) or is_generic(q) for q in values)
@@ -0,0 +1,44 @@
import re
# Expression from https://github.com/pypa/packaging
VERSION_PATTERN = r"""
v?
(?:
(?:(?P<epoch>[0-9]+)!)? # epoch
(?P<release>[0-9]+(?:\.[0-9]+)*) # release segment
(?P<pre> # pre-release
[-_\.]?
(?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview))
[-_\.]?
(?P<pre_n>[0-9]+)?
)?
(?P<post> # post release
(?:-(?P<post_n1>[0-9]+))
|
(?:
[-_\.]?
(?P<post_l>post|rev|r)
[-_\.]?
(?P<post_n2>[0-9]+)?
)
)?
(?P<dev> # dev release
[-_\.]?
(?P<dev_l>dev)
[-_\.]?
(?P<dev_n>[0-9]+)?
)?
)
(?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version
"""
PATTERN = re.compile(
r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE
)
def get_version(version) -> tuple[int, ...]:
match = PATTERN.search(version)
if not match:
raise ValueError(f"Invalid version: {version}")
return tuple(map(int, match.group("release").split(".")))