421a664336
- Remove legacy provider profiles, admin-token auth, /model command, model picker widget, and config.yaml LLM fields (design doc section 10) - Wire CLI/channels/cron and async sub-agents through the local snapshot entry; run creation rejects model config outside runtime_snapshot_id - Add periodic run-snapshot TTL cleanup to the config service lifespan - Isolate tests from the real config dir and activate the registry where run/model paths fail closed in bootstrap Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
95 lines
2.7 KiB
Python
95 lines
2.7 KiB
Python
"""Non-interactive preset container + questionary navigation helpers."""
|
|
|
|
from __future__ import annotations
|
|
|
|
from typing import Any
|
|
|
|
|
|
def install_navigation_keys(question) -> None:
|
|
"""Add keyboard shortcuts on a questionary select ``Question``.
|
|
|
|
Bindings (merged in front of questionary's defaults — Ctrl+C/Ctrl+D still
|
|
cancel the wizard):
|
|
|
|
- ``→`` — accept the option under the cursor and advance (mirrors Enter).
|
|
"""
|
|
from prompt_toolkit.key_binding import KeyBindings, merge_key_bindings
|
|
|
|
kb = KeyBindings()
|
|
|
|
@kb.add("right", eager=True)
|
|
def _confirm(event):
|
|
try:
|
|
from questionary.prompts.common import InquirerControl
|
|
except ImportError: # pragma: no cover
|
|
return
|
|
for window in event.app.layout.find_all_windows():
|
|
ctrl = getattr(window, "content", None)
|
|
if isinstance(ctrl, InquirerControl):
|
|
pointed = ctrl.get_pointed_at()
|
|
ctrl.is_answered = True
|
|
event.app.exit(result=pointed.value)
|
|
return
|
|
|
|
question.application.key_bindings = merge_key_bindings(
|
|
[kb, question.application.key_bindings]
|
|
)
|
|
|
|
|
|
from contextlib import contextmanager # noqa: E402
|
|
|
|
|
|
@contextmanager
|
|
def select_navigation_active():
|
|
"""Bind ``→`` to confirm on every ``questionary.select`` in the block.
|
|
|
|
``checkbox`` is NOT wrapped: the shared ``→`` handler returns a single
|
|
value, but checkbox must return a list of checked items.
|
|
"""
|
|
import questionary
|
|
|
|
original = questionary.select
|
|
|
|
def _wrapped(*args, **kwargs):
|
|
q = original(*args, **kwargs)
|
|
try:
|
|
install_navigation_keys(q)
|
|
except Exception:
|
|
# Don't let a stray keybinding error block the wizard.
|
|
pass
|
|
return q
|
|
|
|
questionary.select = _wrapped
|
|
try:
|
|
yield
|
|
finally:
|
|
questionary.select = original
|
|
|
|
|
|
class NonInteractivePrompter:
|
|
"""Container for CLI-supplied wizard answers (``--ui``, ``--tavily-key``…).
|
|
|
|
``strict=True`` makes missing presets fatal instead of falling back to
|
|
interactive. Wizard reads ``answers`` / ``skip_set`` / ``strict`` directly.
|
|
"""
|
|
|
|
def __init__(
|
|
self,
|
|
answers: dict[str, Any] | None = None,
|
|
skip_set: set[str] | None = None,
|
|
strict: bool = False,
|
|
):
|
|
self.answers: dict[str, Any] = dict(answers or {})
|
|
self.skip_set: set[str] = set(skip_set or ())
|
|
self.strict: bool = bool(strict)
|
|
|
|
def has(self, prompt_id: str) -> bool:
|
|
return prompt_id in self.answers
|
|
|
|
|
|
__all__ = [
|
|
"NonInteractivePrompter",
|
|
"install_navigation_keys",
|
|
"select_navigation_active",
|
|
]
|