mirror of
https://github.com/razzant/ouroboros.git
synced 2026-08-28 21:12:36 +00:00
All 21 window.prompt/confirm/alert sites across web/modules migrate to the
in-app openConfirmDialog (owner decision: the full class, not just the broken
sites), with a new single-button alert mode in confirm_dialog.js. This fixes
the two DEAD window.prompt sites on the macOS desktop shell — the cocoa shell
has no prompt delegate, so marketplace version updates and evolution campaign
objectives silently returned null there — while preserving each site's
contract: empty update version = latest, evolution cancel = do NOT start a
campaign, and the /panic critical control's complete confirm-and-send flow is
the injectable, node-tested chat.js::confirmAndSendPanic. Superseding an
INPUT dialog resolves the documented {confirmed:false, value:''} instead of a
bare false. A static quick-CI gate bans the native dialog trio from
web/modules so the class stays closed, and the canonical rule lives in
DEVELOPMENT.md with the confirm_dialog.js authority mapped in ARCHITECTURE.
Harness Accounts (#125) fetches immediately on page show, re-checks on
tab/page activation, and login polling backs off 6→30s and honestly gives up
into the existing unconfirmed verdict after 10 consecutive failures. The
login lifecycle is fully serialized (plan decision C7): ONE transition lock
covers start and dismiss, a new login starts only after the previous job is
terminal or provably cancelled (gone only on ok/404/410 — a 5xx or network
death refuses the restart instead of orphaning a live job server-side), an
unproven cancel keeps the card and the job id with a transient note that the
next successful poll read clears, the Retry button leaves the poll armed as
the recovery path, and both cancel continuations re-check the terminal
snapshot after their await so a settled job is never frozen behind a stale
cancel error — with the lost-contact verdict explicitly NOT counting as
proof of settlement (loginSettleProven). Six real-Chromium behavioral tests
pin the races, mutation-checked. Deleting every reviewer-slot row and saving
(#126) now surfaces the backend's 400 instead of pretending success. The
desktop pywebview-bridge branches in settings.js stay untouched by design.
Co-authored-by: Ouroboros <311266734+ouroboros-agent@users.noreply.github.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
83 lines
3.6 KiB
Python
83 lines
3.6 KiB
Python
"""Static class ban: no native browser dialogs in ``web/modules``.
|
|
|
|
pywebview's WKWebView implements no ``window.prompt`` (it answers ``null``
|
|
silently — a dead control on the macOS desktop app), and native
|
|
``confirm()``/``alert()`` render OS-modal chrome outside the design system.
|
|
The whole class is therefore banned in favor of the in-house
|
|
``openConfirmDialog`` (input mode replaces prompt, ``alert: true`` replaces
|
|
alert) — owner decision Б2-2, v6.90.3 full-class migration.
|
|
|
|
Pattern follows ``tests/test_mcp_ui_static.py``: read the sources and assert
|
|
the structural fact — no browser needed, so quick CI enforces the ban
|
|
automatically.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import pathlib
|
|
import re
|
|
|
|
|
|
REPO_ROOT = pathlib.Path(__file__).resolve().parents[1]
|
|
WEB_MODULES = REPO_ROOT / "web" / "modules"
|
|
|
|
# A real native-dialog CALL:
|
|
# * ``window.prompt(`` / ``window . confirm(`` / ``window.alert(``, or
|
|
# * bare ``prompt(`` / ``confirm(`` / ``alert(`` NOT preceded by an
|
|
# identifier character or ``.``.
|
|
# Deliberate non-matches:
|
|
# * ``openConfirmDialog(`` — the name continues past ``confirm``;
|
|
# * ``promptProfileName(`` etc. — same;
|
|
# * ``foo.confirm(`` — a method on our own object (``.`` excluded);
|
|
# * ``alert: true`` — an option, not a call.
|
|
NATIVE_DIALOG_CALL = re.compile(
|
|
r"window\s*\.\s*(?:prompt|confirm|alert)\s*\("
|
|
r"|(?<![\w$.])(?:prompt|confirm|alert)\s*\("
|
|
)
|
|
|
|
def _code_lines(source: str) -> list[tuple[int, str]]:
|
|
"""Source lines in code position: full-line ``//``/``*`` comment lines are
|
|
skipped, nothing else is stripped.
|
|
|
|
Deliberately NO block-comment blanking: a ``/*...*/`` DOTALL sweep cannot
|
|
tell a comment opener from the same two characters inside a string, and
|
|
``accept="*/*"`` in chat.js opened a pseudo comment that blanked 403 lines
|
|
of real code — a hole in the only automated enforcement of this class.
|
|
Trailing ``//`` comments are likewise not stripped (a ``//`` inside a URL
|
|
string would truncate real code). Both choices over-approximate in the
|
|
safe direction: a call smuggled into a comment is reported, which for a
|
|
class ban is a nuisance, while a blind region is a defect."""
|
|
lines: list[tuple[int, str]] = []
|
|
for lineno, line in enumerate(source.splitlines(), 1):
|
|
stripped = line.strip()
|
|
if stripped.startswith("//") or stripped.startswith("*"):
|
|
continue
|
|
lines.append((lineno, line))
|
|
return lines
|
|
|
|
|
|
def test_no_native_dialog_calls_in_web_modules() -> None:
|
|
sources = sorted(WEB_MODULES.glob("**/*.js"))
|
|
assert sources, f"no JS modules found under {WEB_MODULES}"
|
|
violations: list[str] = []
|
|
for path in sources:
|
|
for lineno, line in _code_lines(path.read_text(encoding="utf-8")):
|
|
if NATIVE_DIALOG_CALL.search(line):
|
|
violations.append(
|
|
f"{path.relative_to(REPO_ROOT)}:{lineno}: {line.strip()}"
|
|
)
|
|
assert not violations, (
|
|
"Native browser dialogs are banned in web/modules: window.prompt is a "
|
|
"silent no-op under pywebview (macOS desktop), and confirm()/alert() "
|
|
"bypass the design system. Use openConfirmDialog from "
|
|
"web/modules/confirm_dialog.js (input mode for prompt, alert:true for "
|
|
"alert).\n" + "\n".join(violations)
|
|
)
|
|
|
|
|
|
def test_confirm_dialog_offers_the_alert_mode() -> None:
|
|
"""The replacement the ban points at must actually exist: the in-house
|
|
dialog exposes the alert option the migrated alert() sites rely on."""
|
|
source = (WEB_MODULES / "confirm_dialog.js").read_text(encoding="utf-8")
|
|
assert "alert = false" in source
|
|
assert "openConfirmDialog" in source
|