feat(scripts): add MOBILE_FIRST_MARKERS + _check_mobile_first check

This commit is contained in:
opencode-agent 2026-08-05 03:34:27 +00:00
parent 43975cb593
commit e4ddbb38af
2 changed files with 62 additions and 0 deletions

View file

@ -673,6 +673,50 @@ def _check_frontend_stack(ctx: RepoCtx) -> CheckResult | None:
return CheckResult(CheckStatus.OK, "frontend stack", "Tailwind + shadcn-svelte + TS detected") return CheckResult(CheckStatus.OK, "frontend stack", "Tailwind + shadcn-svelte + TS detected")
def _check_mobile_first(ctx: RepoCtx) -> CheckResult | None:
"""Fullstack mobile-first guarantee (issue #278): PWA manifest + mobile
Playwright + axe-core accessibility.
Returns ``None`` if ``frontend/package.json`` does not exist (the missing
package.json WARN is surfaced separately by ``_check_type_specific_structure``).
Returns ``None`` for non-fullstack types the caller only invokes this for
FULLSTACK. Otherwise returns OK when all markers are present, or WARN with
the missing marker list (never FAIL issue #275 all-WARN contract).
Markers (``MOBILE_FIRST_MARKERS``):
* ``frontend/static/manifest.webmanifest`` exists
* ``frontend/src/app.html`` contains both "viewport" and "manifest"
* ``frontend/tests/e2e/mobile.spec.ts`` exists
* ``frontend/tests/e2e/accessibility.spec.ts`` exists
* ``@axe-core/playwright`` in ``frontend/package.json`` devDependencies
"""
pkg_path = ctx.root / "frontend" / "package.json"
if not pkg_path.exists():
return None
missing: list[str] = []
for rel in project_contract.MOBILE_FIRST_MARKERS["fullstack_files"]:
if not (ctx.root / rel).exists():
missing.append(rel)
app_html = read_text("frontend/src/app.html", ctx) or ""
for marker in project_contract.MOBILE_FIRST_MARKERS["fullstack_app_html_markers"]:
if marker not in app_html:
missing.append(f"frontend/src/app.html ({marker})")
try:
pkg = json.loads(pkg_path.read_text(encoding="utf-8-sig"))
except (json.JSONDecodeError, OSError):
pkg = {}
dev_deps = pkg.get("devDependencies", {}) if isinstance(pkg, dict) else {}
if "@axe-core/playwright" not in dev_deps:
missing.append("@axe-core/playwright in package.json devDependencies")
if missing:
return CheckResult(
CheckStatus.WARN,
"mobile-first",
"missing " + ", ".join(missing),
)
return CheckResult(CheckStatus.OK, "mobile-first", "PWA + mobile Playwright + a11y detected")
def _check_type_specific_structure(ptype: ProjectType, ctx: RepoCtx) -> list[CheckResult]: def _check_type_specific_structure(ptype: ProjectType, ctx: RepoCtx) -> list[CheckResult]:
"""Type-specific extra checks beyond the expected dirs list.""" """Type-specific extra checks beyond the expected dirs list."""
results: list[CheckResult] = [] results: list[CheckResult] = []
@ -688,6 +732,9 @@ def _check_type_specific_structure(ptype: ProjectType, ctx: RepoCtx) -> list[Che
frontend_stack = _check_frontend_stack(ctx) frontend_stack = _check_frontend_stack(ctx)
if frontend_stack is not None: if frontend_stack is not None:
results.append(frontend_stack) results.append(frontend_stack)
mobile = _check_mobile_first(ctx)
if mobile is not None:
results.append(mobile)
if ptype == ProjectType.CLI: if ptype == ProjectType.CLI:
results.append(_check_cli_package(ctx)) results.append(_check_cli_package(ctx))
flat = _check_flat_layout(ptype, ctx) flat = _check_flat_layout(ptype, ctx)

View file

@ -78,3 +78,18 @@ FRONTEND_STACK_MARKERS: dict[str, list[str]] = {
"fullstack_package_deps": ["tailwindcss", "bits-ui"], "fullstack_package_deps": ["tailwindcss", "bits-ui"],
"fullstack_files": ["frontend/components.json", "frontend/tsconfig.json"], "fullstack_files": ["frontend/components.json", "frontend/tsconfig.json"],
} }
# Fullstack mobile-first markers (project-status _check_mobile_first, issue #278).
# Distinct from FRONTEND_STACK_MARKERS so the stack check stays focused on the
# Tailwind/shadcn/TS trio. Keys:
# fullstack_files — paths (relative to repo root) that must exist
# for PWA + mobile Playwright + a11y to be present.
# fullstack_app_html_markers — substrings that must appear in app.html <head>.
MOBILE_FIRST_MARKERS: dict[str, list[str]] = {
"fullstack_files": [
"frontend/static/manifest.webmanifest",
"frontend/tests/e2e/mobile.spec.ts",
"frontend/tests/e2e/accessibility.spec.ts",
],
"fullstack_app_html_markers": ["viewport", "manifest"],
}