feat(webui): add guided setup flows

* feat(channels): add guided setup flows

* test(channels): preserve setup config values

* fix(channels): reflect saved setup state

* refactor(channels): simplify setup state metadata

* fix(channels): harden setup lifecycle

* refactor(channels): centralize setup contracts

* fix(channels): route setup actions through webui shim

* fix(channels): adapt settings for compact screens

* fix(models): preserve default preset display

* feat(models): add curated Codex catalog

* fix(webui): stop attached gateway on interrupt

* fix(webui): simplify apps catalog

* docs(webui): clarify apps and runtime features

* feat(settings): add guided capability setup

* fix(webui): harden setup and managed services

* test: keep managed runtime checks portable

* test: scope POSIX runtime coverage

* fix(webui): simplify file settings

* feat(files): bundle document reading

* fix(webui): harden setup request boundaries

* fix(webui): prevent channel setup status squeeze

* fix(settings): group provider compatibility aliases

* refactor(settings): remove redundant setup surfaces

* fix(webui): harden guided setup lifecycle

* fix(webui): preserve channel setup compatibility
This commit is contained in:
Xubin Ren
2026-07-13 13:11:46 +08:00
committed by GitHub
parent 791c7fd505
commit fe0717b385
92 changed files with 15058 additions and 1311 deletions
+48 -3
View File
@@ -170,7 +170,52 @@ def revoke(channel: str, sender_id: str) -> bool:
_save(data)
logger.info("Revoked {} from {}", sid, channel)
return True
return False
return False
def revoke_channel(channel: str) -> int:
"""Remove all approved sender IDs for *channel*.
Returns the number of approved senders that were removed.
"""
with _LOCK:
data = _load()
approved: dict[str, set[str]] = data.get("approved", {})
users = approved.pop(channel, set())
if not users:
return 0
_save(data)
logger.info("Revoked {} approved sender(s) from {}", len(users), channel)
return len(users)
def clear_channel(channel: str) -> dict[str, int]:
"""Remove approved senders and pending requests for *channel*."""
with _LOCK:
data = _load()
approved: dict[str, set[str]] = data.get("approved", {})
approved_users = approved.pop(channel, set())
pending: dict[str, Any] = data.get("pending", {})
pending_codes = [
code
for code, info in pending.items()
if str(info.get("channel", "")) == channel
]
for code in pending_codes:
del pending[code]
if not approved_users and not pending_codes:
return {"approved": 0, "pending": 0}
_save(data)
logger.info(
"Cleared {} approved sender(s) and {} pending request(s) from {}",
len(approved_users),
len(pending_codes),
channel,
)
return {"approved": len(approved_users), "pending": len(pending_codes)}
def get_approved(channel: str) -> list[str]:
@@ -185,8 +230,8 @@ def format_pairing_reply(code: str) -> str:
return (
"Hi there! This assistant only responds to approved users.\n\n"
f"Your pairing code is: `{code}`\n\n"
"To get access, ask the owner to approve this code:\n"
f"- In this chat: send `/pairing approve {code}`"
"To get access, ask the owner to approve this request in the nanobot WebUI.\n"
f"If the WebUI is not available, the owner can also send `/pairing approve {code}`."
)