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,78 @@
from __future__ import annotations
from functools import wraps
from inspect import isawaitable
from typing import TYPE_CHECKING, Optional, Union
from jinja2 import Environment
from sanic.compat import Header
from sanic.request import Request
from sanic.response import HTTPResponse
from sanic_ext.extensions.templating.render import (
LazyResponse,
TemplateResponse,
)
if TYPE_CHECKING:
from sanic_ext import Config
class Templating:
def __init__(self, environment: Environment, config: Config) -> None:
self.environment = environment
self.config = config
def template(
self,
file_name: str,
status: int = 200,
headers: Optional[Union[Header, dict[str, str]]] = None,
content_type: str = "text/html; charset=utf-8",
**kwargs,
):
template = self.environment.get_template(file_name)
render = (
template.render_async
if self.config.TEMPLATING_ENABLE_ASYNC
else template.render
)
def decorator(f):
@wraps(f)
async def decorated_function(*args, **kwargs):
context = f(*args, **kwargs)
if isawaitable(context):
context = await context
if isinstance(context, HTTPResponse) and not isinstance(
context, TemplateResponse
):
return context
# TODO
# - Allow each of these to be a callable that is executed here
params = {
"status": status,
"content_type": content_type,
"headers": headers,
}
if isinstance(context, LazyResponse):
for attr in ("status", "headers", "content_type"):
value = getattr(context, attr, None)
if value:
params[attr] = value
context = context.context
context["request"] = Request.get_current()
content = render(**context)
if isawaitable(content):
content = await content
return HTTPResponse(content, **params)
return decorated_function
return decorator
@@ -0,0 +1,57 @@
from __future__ import annotations
import os
from collections import abc
from collections.abc import Sequence
from pathlib import Path
from typing import TYPE_CHECKING, Union
from jinja2 import (
Environment,
FileSystemLoader,
__version__,
select_autoescape,
)
from sanic_ext.extensions.templating.engine import Templating
from ..base import Extension
if TYPE_CHECKING:
from sanic_ext import Extend
class TemplatingExtension(Extension):
name = "templating"
def startup(self, bootstrap: Extend) -> None:
self._add_template_paths_to_reloader(
self.config.TEMPLATING_PATH_TO_TEMPLATES
)
loader = FileSystemLoader(self.config.TEMPLATING_PATH_TO_TEMPLATES)
if not hasattr(bootstrap, "environment"):
bootstrap.environment = Environment(
loader=loader,
autoescape=select_autoescape(),
enable_async=self.config.TEMPLATING_ENABLE_ASYNC,
)
if not hasattr(bootstrap, "templating"):
bootstrap.templating = Templating(
environment=bootstrap.environment, config=self.config
)
bootstrap.templating.environment.globals["url_for"] = self.app.url_for
def label(self):
return f"jinja2=={__version__}"
def _add_template_paths_to_reloader(
self, path: Union[str, os.PathLike, Sequence[Union[str, os.PathLike]]]
) -> None:
if not isinstance(path, abc.Iterable) or isinstance(path, str):
path = [path]
for item in path:
self.app.state.reload_dirs.add(Path(item))
@@ -0,0 +1,105 @@
from __future__ import annotations
from inspect import isawaitable
from typing import TYPE_CHECKING, Any, Optional, Union
from sanic import Sanic
from sanic.compat import Header
from sanic.exceptions import SanicException
from sanic.request import Request
from sanic.response import HTTPResponse
from sanic_ext.exceptions import ExtensionNotFound
if TYPE_CHECKING:
from jinja2 import Environment
class TemplateResponse(HTTPResponse): ...
class LazyResponse(TemplateResponse):
__slots__ = (
"body",
"status",
"content_type",
"headers",
"_cookies",
"context",
)
def __init__(
self,
context: dict[str, Any],
status: int = 0,
headers: Optional[Union[Header, dict[str, str]]] = None,
content_type: Optional[str] = None,
):
super().__init__(
content_type=content_type, status=status, headers=headers
)
self.context = context
async def render(
template_name: str = "",
status: int = 200,
headers: Optional[dict[str, str]] = None,
content_type: str = "text/html; charset=utf-8",
app: Optional[Sanic] = None,
environment: Optional[Environment] = None,
context: Optional[dict[str, Any]] = None,
*,
template_source: str = "",
) -> TemplateResponse:
if app is None:
try:
app = Sanic.get_app()
except SanicException as e:
raise SanicException(
"Cannot render template beause locating the Sanic application "
"was ambiguous. Please return render(..., app=some_app)."
) from e
if template_name and template_source:
raise SanicException(
"You must provide template_name OR template_source, not both."
)
if environment is None:
try:
environment = app.ext.environment
except AttributeError:
raise ExtensionNotFound(
"The Templating extension does not appear to be enabled. "
"Perhaps jinja2 is not installed."
)
kwargs = context if context else {}
kwargs["request"] = Request.get_current()
if template_name or template_source:
template = (
environment.get_template(template_name)
if template_name
else environment.from_string(template_source)
)
render = (
template.render_async
if app.config.TEMPLATING_ENABLE_ASYNC
else template.render
)
content = render(**kwargs)
if isawaitable(content):
content = await content # type: ignore
return TemplateResponse( # type: ignore
content, status=status, headers=headers, content_type=content_type
)
else:
return LazyResponse(
kwargs, status=status, headers=headers, content_type=content_type
)