kctl-react 0.10.2__tar.gz → 0.10.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. {kctl_react-0.10.2 → kctl_react-0.10.4}/PKG-INFO +2 -2
  2. {kctl_react-0.10.2 → kctl_react-0.10.4}/pyproject.toml +7 -1
  3. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/__init__.py +1 -1
  4. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/cli.py +3 -5
  5. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/cap/__init__.py +40 -0
  6. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/cap/_helpers.py +0 -1
  7. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/cap/lifecycle.py +0 -1
  8. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/compliance.py +13 -15
  9. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/doctor_cmd.py +0 -1
  10. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/ui_audit/__init__.py +2 -1
  11. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/ui_audit/theming.py +12 -5
  12. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/callbacks.py +2 -1
  13. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/checks/endpoints.py +4 -1
  14. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/imports.py +9 -10
  15. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/providers.py +4 -1
  16. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/ui_standard.py +1 -1
  17. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/engine.py +1 -1
  18. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/discovery.py +2 -1
  19. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_api_check.py +10 -16
  20. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_api_health.py +4 -8
  21. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_commands.py +9 -2
  22. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_compliance.py +17 -28
  23. {kctl_react-0.10.2 → kctl_react-0.10.4}/.gitignore +0 -0
  24. {kctl_react-0.10.2 → kctl_react-0.10.4}/README.md +0 -0
  25. {kctl_react-0.10.2 → kctl_react-0.10.4}/e2e/.gitignore +0 -0
  26. {kctl_react-0.10.2 → kctl_react-0.10.4}/e2e/README.md +0 -0
  27. {kctl_react-0.10.2 → kctl_react-0.10.4}/e2e/fixtures/auth.ts +0 -0
  28. {kctl_react-0.10.2 → kctl_react-0.10.4}/e2e/package.json +0 -0
  29. {kctl_react-0.10.2 → kctl_react-0.10.4}/e2e/playwright.config.ts +0 -0
  30. {kctl_react-0.10.2 → kctl_react-0.10.4}/e2e/tests/smoke/connectivity.spec.ts +0 -0
  31. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/__main__.py +0 -0
  32. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/_register.py +1 -1
  33. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/__init__.py +0 -0
  34. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/a11y.py +0 -0
  35. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/affected.py +0 -0
  36. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/apps.py +1 -1
  37. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/build.py +0 -0
  38. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/bundle_cmd.py +0 -0
  39. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/cap/devices.py +0 -0
  40. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/cap/environment.py +1 -1
  41. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/cap/signing.py +0 -0
  42. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/clean.py +0 -0
  43. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/codegen.py +0 -0
  44. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/config_cmd.py +0 -0
  45. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/dashboard.py +0 -0
  46. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/deploy.py +0 -0
  47. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/deps.py +0 -0
  48. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/dev.py +0 -0
  49. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/docker_cmd.py +0 -0
  50. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/doctor.py +0 -0
  51. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/e2e.py +0 -0
  52. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/env.py +0 -0
  53. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/i18n.py +0 -0
  54. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/lint.py +0 -0
  55. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/maintenance.py +0 -0
  56. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/monitor_cmd.py +0 -0
  57. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/observe.py +0 -0
  58. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/packages.py +0 -0
  59. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/perf.py +0 -0
  60. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/pipeline.py +0 -0
  61. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/pwa.py +0 -0
  62. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/scaffold.py +0 -0
  63. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/security.py +0 -0
  64. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/state.py +0 -0
  65. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/test_cmd.py +0 -0
  66. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/commands/ui_audit/antipatterns.py +0 -0
  67. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/__init__.py +0 -0
  68. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/analyzers.py +0 -0
  69. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/__init__.py +0 -0
  70. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/__init__.py +0 -0
  71. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/checks/__init__.py +0 -0
  72. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/checks/envelope.py +0 -0
  73. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/checks/naming.py +0 -0
  74. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/checks/params.py +0 -0
  75. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/checks/requests.py +0 -0
  76. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/checks/types.py +0 -0
  77. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/hooks.py +0 -0
  78. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/matcher.py +0 -0
  79. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_check/schema.py +0 -0
  80. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/__init__.py +0 -0
  81. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/checks/__init__.py +0 -0
  82. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/checks/auth.py +0 -0
  83. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/checks/reachable.py +0 -0
  84. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/checks/response.py +0 -0
  85. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/checks/timing.py +0 -0
  86. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/client.py +0 -0
  87. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/api_health/sampler.py +0 -0
  88. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/__init__.py +0 -0
  89. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/api.py +0 -0
  90. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/codegen.py +0 -0
  91. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/darkmode.py +0 -0
  92. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/errors.py +0 -0
  93. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/features.py +0 -0
  94. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/i18n_check.py +0 -0
  95. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/navigation.py +0 -0
  96. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/practices.py +0 -0
  97. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/pwa.py +0 -0
  98. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/responsive.py +0 -0
  99. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/scripts.py +0 -0
  100. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/shadcn.py +0 -0
  101. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/structure.py +0 -0
  102. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/testing.py +0 -0
  103. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/theme.py +0 -0
  104. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/checks/vite.py +0 -0
  105. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/exceptions_map.py +0 -0
  106. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/fixes/__init__.py +0 -0
  107. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/fixes/codegen_fix.py +0 -0
  108. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/fixes/i18n_fix.py +0 -0
  109. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/fixes/imports_fix.py +0 -0
  110. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/fixes/structure_fix.py +0 -0
  111. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/fixes/theme_fix.py +0 -0
  112. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/compliance/models.py +0 -0
  113. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/config.py +0 -0
  114. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/exceptions.py +0 -0
  115. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/git.py +0 -0
  116. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/history.py +0 -0
  117. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/output.py +0 -0
  118. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/plugins.py +0 -0
  119. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/core/runner.py +0 -0
  120. {kctl_react-0.10.2 → kctl_react-0.10.4}/src/kctl_react/py.typed +0 -0
  121. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/conftest.py +0 -0
  122. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_analyzers.py +0 -0
  123. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_cap.py +0 -0
  124. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_config.py +0 -0
  125. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_doctor_ai_summary.py +0 -0
  126. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_exceptions.py +0 -0
  127. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_output.py +0 -0
  128. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_pipeline.py +0 -0
  129. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_runner.py +0 -0
  130. {kctl_react-0.10.2 → kctl_react-0.10.4}/tests/test_standard.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: kctl-react
3
- Version: 0.10.2
3
+ Version: 0.10.4
4
4
  Summary: Kodemeio React CLI — manage the kodemeio-react monorepo
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: httpx>=0.28.0
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "kctl-react"
7
- version = "0.10.2"
7
+ version = "0.10.4"
8
8
  description = "Kodemeio React CLI — manage the kodemeio-react monorepo"
9
9
  requires-python = ">=3.12"
10
10
  dependencies = [
@@ -40,6 +40,12 @@ packages = ["src/kctl_react"]
40
40
  target-version = "py312"
41
41
  line-length = 120
42
42
 
43
+ [tool.ruff.lint]
44
+ # Workspace lint policy (mirrors the root pyproject). Without this the bare
45
+ # [tool.ruff] block above opts the package into ruff's entire catalogue rather
46
+ # than the fleet standard, which is how ~1500 unadopted-rule findings appeared.
47
+ select = ["E", "F", "I", "W", "UP", "B", "SIM"]
48
+
43
49
  [tool.mypy]
44
50
  python_version = "3.12"
45
51
  strict = true
@@ -1,3 +1,3 @@
1
1
  """kctl-react: Kodemeio React Monorepo CLI."""
2
2
 
3
- __version__ = "0.10.2"
3
+ __version__ = "0.10.4"
@@ -2,18 +2,16 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
-
6
5
  from typing import Annotated
7
6
 
8
7
  import typer
9
- from kctl_lib import KctlError, handle_cli_error
10
- from kctl_lib import cli_entrypoint, register_introspection_commands
8
+ from kctl_lib import KctlError, cli_entrypoint, handle_cli_error, register_introspection_commands
9
+ from kctl_lib.self_update import notify_if_outdated
11
10
 
12
11
  from kctl_react import __version__
12
+ from kctl_react._register import register_all
13
13
  from kctl_react.core.callbacks import AppContext
14
14
  from kctl_react.core.plugins import discover_and_load_plugins
15
- from kctl_react._register import register_all
16
- from kctl_lib.self_update import notify_if_outdated
17
15
 
18
16
 
19
17
  def version_callback(value: bool) -> None:
@@ -41,6 +41,46 @@ from kctl_react.commands.cap.environment import _fix_android_project, add, docto
41
41
  from kctl_react.commands.cap.lifecycle import build, dev, open_ide, run_native, sync
42
42
  from kctl_react.commands.cap.signing import _keystore_path, _write_signing_config, keystore
43
43
 
44
+ # Re-exported on purpose. The facet split is an implementation detail: tests and
45
+ # callers import these helpers from `kctl_react.commands.cap`, so declaring the
46
+ # surface here keeps them from reading as dead imports.
47
+ __all__ = [
48
+ "_check_cap_version_match",
49
+ "_find_apk",
50
+ "_fix_android_project",
51
+ "_get_adb_path",
52
+ "_get_android_min_sdk",
53
+ "_get_app_id",
54
+ "_get_gradle_version",
55
+ "_get_java_major_version",
56
+ "_get_pkg_deps",
57
+ "_has_capacitor",
58
+ "_has_platform",
59
+ "_keystore_path",
60
+ "_list_devices",
61
+ "_preflight",
62
+ "_run_cap",
63
+ "_show_checks",
64
+ "_validate_environment",
65
+ "_write_signing_config",
66
+ "add",
67
+ "app",
68
+ "build",
69
+ "dev",
70
+ "devices",
71
+ "doctor",
72
+ "emulator",
73
+ "init",
74
+ "install",
75
+ "keystore",
76
+ "launch",
77
+ "logs",
78
+ "open_ide",
79
+ "run_native",
80
+ "status",
81
+ "sync",
82
+ ]
83
+
44
84
  app = typer.Typer(help="Capacitor native app management (Android/iOS).")
45
85
 
46
86
  app.command()(status)
@@ -11,7 +11,6 @@ from typing import Any
11
11
 
12
12
  import typer
13
13
 
14
- from kctl_react.core.exceptions import CommandError
15
14
  from kctl_react.core.runner import run
16
15
 
17
16
  _DEFAULT_APP_ID_PREFIX = "io.kodeme"
@@ -2,7 +2,6 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from pathlib import Path
6
5
  from typing import Annotated
7
6
 
8
7
  import typer
@@ -9,10 +9,10 @@ from typing import Annotated
9
9
  import typer
10
10
 
11
11
  from kctl_react.core.callbacks import AppContext
12
- from kctl_react.core.discovery import get_app_dir
13
12
  from kctl_react.core.compliance.engine import ComplianceEngine
14
13
  from kctl_react.core.compliance.fixes import apply_fixes
15
14
  from kctl_react.core.compliance.models import AppReport, CategoryResult
15
+ from kctl_react.core.discovery import get_app_dir
16
16
 
17
17
  logger = logging.getLogger(__name__)
18
18
 
@@ -56,7 +56,8 @@ def _audit_single(actx: AppContext, report: AppReport) -> None:
56
56
  if cat.violations:
57
57
  vcount = len(cat.violations)
58
58
  out.text(
59
- f" [yellow]![/yellow] {cat.label:<20s} {cat.score}/{cat.max_points} ({vcount} violation{'s' if vcount != 1 else ''})"
59
+ f" [yellow]![/yellow] {cat.label:<20s} {cat.score}/{cat.max_points} ({vcount} "
60
+ f"violation{'s' if vcount != 1 else ''})"
60
61
  )
61
62
  else:
62
63
  out.text(f" [green]\u2713[/green] {cat.label:<20s} {cat.score}/{cat.max_points}")
@@ -338,10 +339,7 @@ def _run_api_check_for_app(
338
339
  match = match_hooks_to_schema(hooks, schema)
339
340
 
340
341
  # Select checkers (filtered by --categories if given)
341
- if cat_list:
342
- checkers = [CHECKER_MAP[c] for c in cat_list if c in CHECKER_MAP]
343
- else:
344
- checkers = list(ALL_API_CHECKERS)
342
+ checkers = [CHECKER_MAP[c] for c in cat_list if c in CHECKER_MAP] if cat_list else list(ALL_API_CHECKERS)
345
343
 
346
344
  categories: list[CategoryResult] = []
347
345
  for checker in checkers:
@@ -367,8 +365,12 @@ def _run_api_health_for_app(
367
365
  parse_schema,
368
366
  )
369
367
  from kctl_react.core.compliance.api_health import run_health_checks
370
- from kctl_react.core.compliance.api_health.checks import AuthChecker
371
- from kctl_react.core.compliance.api_health.checks import ReachableChecker, ResponseChecker, TimingChecker
368
+ from kctl_react.core.compliance.api_health.checks import (
369
+ AuthChecker,
370
+ ReachableChecker,
371
+ ResponseChecker,
372
+ TimingChecker,
373
+ )
372
374
  from kctl_react.core.compliance.api_health.client import HealthClient
373
375
  from kctl_react.core.compliance.api_health.sampler import sample_endpoints
374
376
 
@@ -391,9 +393,8 @@ def _run_api_health_for_app(
391
393
  client = HealthClient(base_url=base_url, token=token, timeout=timeout)
392
394
 
393
395
  # Authenticate if no token provided
394
- if not client.token:
395
- if not client.authenticate(app_path, app_name):
396
- pass
396
+ if not client.token and not client.authenticate(app_path, app_name):
397
+ pass
397
398
 
398
399
  endpoints = sample_endpoints(schema)
399
400
  results = run_health_checks(client, endpoints)
@@ -408,10 +409,7 @@ def _run_api_health_for_app(
408
409
  "timing": lambda: TimingChecker().check(results, threshold=timeout),
409
410
  }
410
411
 
411
- if cat_list:
412
- selected = [c for c in cat_list if c in checker_instances]
413
- else:
414
- selected = list(checker_instances.keys())
412
+ selected = [c for c in cat_list if c in checker_instances] if cat_list else list(checker_instances.keys())
415
413
 
416
414
  for name in selected:
417
415
  categories.append(checker_instances[name]())
@@ -12,7 +12,6 @@ import shutil
12
12
  from dataclasses import dataclass
13
13
 
14
14
  import typer
15
-
16
15
  from kctl_lib.doctor_base import CheckResult, DoctorCheck
17
16
 
18
17
 
@@ -11,7 +11,8 @@ from __future__ import annotations
11
11
  import typer
12
12
 
13
13
  from .antipatterns import app as _antipatterns_app
14
- from .theming import _build_updated_globals, _extract_css_blocks, app as _theming_app
14
+ from .theming import _build_updated_globals, _extract_css_blocks
15
+ from .theming import app as _theming_app
15
16
 
16
17
  app = typer.Typer(help="UI component audit and shadcn compliance.")
17
18
 
@@ -319,12 +319,19 @@ def preset(
319
319
  actx: AppContext = ctx.obj
320
320
  out = actx.output
321
321
 
322
- # Validate target
323
- if target != "base" and target not in _VALID_APPS:
324
- out.error(f"Invalid target '{target}'. Use 'base' or an app name: {', '.join(sorted(_VALID_APPS))}")
325
- raise typer.Exit(1)
326
-
327
322
  tc_src = actx.project_root / "packages" / "tailwind-config" / "src"
323
+
324
+ # Validate target against the theme files that actually exist, not a
325
+ # hardcoded list. The literal set drifted: it still named sfa/lfa/wms/bia/mrp
326
+ # after those apps were retired, and never learned about erp, tms or
327
+ # terakidz — so `--target erp` was refused for an app whose theme file was
328
+ # sitting right there. _VALID_APPS remains as the fallback for the case
329
+ # where the themes directory cannot be read.
330
+ themes_dir = tc_src / "themes"
331
+ available = {p.stem for p in themes_dir.glob("*.css")} if themes_dir.is_dir() else set(_VALID_APPS)
332
+ if target != "base" and target not in available:
333
+ out.error(f"Invalid target '{target}'. Use 'base' or an app name: {', '.join(sorted(available))}")
334
+ raise typer.Exit(1)
328
335
  globals_path = tc_src / "globals.css"
329
336
  target_path = tc_src / "base-neutral.css" if target == "base" else tc_src / "themes" / f"{target}.css"
330
337
 
@@ -9,7 +9,8 @@ from typing import Any
9
9
  from kctl_lib.callbacks import AppContextBase
10
10
 
11
11
  from kctl_react.core.config import resolve_project_root
12
- from kctl_react.core.discovery import discover_apps, discover_packages, get_app_dir as _get_app_dir
12
+ from kctl_react.core.discovery import discover_apps, discover_packages
13
+ from kctl_react.core.discovery import get_app_dir as _get_app_dir
13
14
 
14
15
 
15
16
  @dataclass
@@ -40,7 +40,10 @@ class EndpointChecker:
40
40
  Violation(
41
41
  file=hook.file,
42
42
  line=hook.line,
43
- message=f"Dead endpoint: {hook.method.upper()} {hook.normalized_url} in {hook.file} — not in OpenAPI schema",
43
+ message=(
44
+ f"Dead endpoint: {hook.method.upper()} {hook.normalized_url} in {hook.file} — not in OpenAPI "
45
+ f"schema"
46
+ ),
44
47
  fix_hint="Remove this API call or add the endpoint to the OpenAPI schema",
45
48
  )
46
49
  )
@@ -66,17 +66,16 @@ class ImportsChecker:
66
66
  )
67
67
 
68
68
  # Direct @/generated/ imports outside types/api.ts
69
- if re.search(r'from\s+["\']@/generated/', line):
70
- if not rel.endswith("types/api.ts"):
71
- violations.append(
72
- Violation(
73
- file=rel,
74
- line=i,
75
- message="Direct @/generated/ import — use @/types/api instead",
76
- fix_hint="Import from @/types/api",
77
- auto_fixable=True,
78
- )
69
+ if re.search("from\\s+[\"\\']@/generated/", line) and not rel.endswith("types/api.ts"):
70
+ violations.append(
71
+ Violation(
72
+ file=rel,
73
+ line=i,
74
+ message="Direct @/generated/ import — use @/types/api instead",
75
+ fix_hint="Import from @/types/api",
76
+ auto_fixable=True,
79
77
  )
78
+ )
80
79
 
81
80
  return CategoryResult(
82
81
  name=self.name,
@@ -72,7 +72,10 @@ class ProviderChecker:
72
72
  violations.append(
73
73
  Violation(
74
74
  file="src/main.tsx",
75
- message=f"Provider order incorrect. Expected: {' > '.join(expected_found)}, got: {' > '.join(found_ordered)}",
75
+ message=(
76
+ f"Provider order incorrect. Expected: {' > '.join(expected_found)}, got: "
77
+ f"{' > '.join(found_ordered)}"
78
+ ),
76
79
  fix_hint="Reorder providers to match expected stack",
77
80
  )
78
81
  )
@@ -141,7 +141,7 @@ class UiStandardChecker:
141
141
  has_datatable = False
142
142
  pages_dir = src / "pages"
143
143
 
144
- for f, content in all_contents.items():
144
+ for _f, content in all_contents.items():
145
145
  if "@kodemeio/ui" in content and "DataTable" in content:
146
146
  has_datatable = True
147
147
 
@@ -52,7 +52,7 @@ class ComplianceEngine:
52
52
  if auto_violations:
53
53
  lines.append(f"```bash\nkctl-react compliance fix {report.app}\n```")
54
54
  lines.append("")
55
- for cat, v in auto_violations:
55
+ for _cat, v in auto_violations:
56
56
  hint = f" -- {v.fix_hint}" if v.fix_hint else ""
57
57
  lines.append(f"- `{v.file}`:{v.line or '?'} {v.message}{hint}")
58
58
  else:
@@ -54,7 +54,8 @@ def discover_apps(root: Path) -> dict[str, dict[str, Any]]:
54
54
  Falls back to flat apps/ scanning for legacy repos.
55
55
 
56
56
  Returns a dict like:
57
- {"sfa": {"port": 4004, "name": "Sales Force Automation", "package": "@kodemeio/sfa", "type": "spa", "path": Path(...)}}
57
+ {"sfa": {"port": 4004, "name": "Sales Force Automation",
58
+ "package": "@kodemeio/sfa", "type": "spa", "path": Path(...)}}
58
59
 
59
60
  Works with any Turbo monorepo — reads package.json for metadata.
60
61
  """
@@ -3,10 +3,19 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  import json
6
+ import json as _json
6
7
  from pathlib import Path
7
8
 
8
- import pytest
9
+ from typer.testing import CliRunner
9
10
 
11
+ from kctl_react.cli import app as cli_app
12
+ from kctl_react.core.compliance.api_check.checks import ALL_API_CHECKERS, CHECKER_MAP
13
+ from kctl_react.core.compliance.api_check.checks.endpoints import EndpointChecker
14
+ from kctl_react.core.compliance.api_check.checks.envelope import EnvelopeChecker
15
+ from kctl_react.core.compliance.api_check.checks.naming import NamingChecker
16
+ from kctl_react.core.compliance.api_check.checks.params import ParamChecker
17
+ from kctl_react.core.compliance.api_check.checks.requests import RequestChecker
18
+ from kctl_react.core.compliance.api_check.checks.types import TypeChecker
10
19
  from kctl_react.core.compliance.api_check.hooks import HookCall, parse_hooks
11
20
  from kctl_react.core.compliance.api_check.matcher import MatchResult, match_hooks_to_schema
12
21
  from kctl_react.core.compliance.api_check.schema import (
@@ -16,7 +25,6 @@ from kctl_react.core.compliance.api_check.schema import (
16
25
  parse_schema,
17
26
  )
18
27
 
19
-
20
28
  # ---------------------------------------------------------------------------
21
29
  # Fixtures
22
30
  # ---------------------------------------------------------------------------
@@ -308,15 +316,6 @@ class TestLoadSchema:
308
316
  # ---------------------------------------------------------------------------
309
317
 
310
318
 
311
- from kctl_react.core.compliance.api_check.checks import ALL_API_CHECKERS, CHECKER_MAP
312
- from kctl_react.core.compliance.api_check.checks.endpoints import EndpointChecker
313
- from kctl_react.core.compliance.api_check.checks.envelope import EnvelopeChecker
314
- from kctl_react.core.compliance.api_check.checks.naming import NamingChecker
315
- from kctl_react.core.compliance.api_check.checks.params import ParamChecker
316
- from kctl_react.core.compliance.api_check.checks.requests import RequestChecker
317
- from kctl_react.core.compliance.api_check.checks.types import TypeChecker
318
-
319
-
320
319
  def _make_hook(
321
320
  *,
322
321
  file: str = "src/api/useProductions.ts",
@@ -567,11 +566,6 @@ class TestCheckerRegistry:
567
566
  # CLI command tests (Typer CliRunner)
568
567
  # ---------------------------------------------------------------------------
569
568
 
570
- import json as _json
571
-
572
- from typer.testing import CliRunner
573
-
574
- from kctl_react.cli import app as cli_app
575
569
 
576
570
  _runner = CliRunner()
577
571
 
@@ -2,10 +2,13 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json as _json
6
+ from pathlib import Path
5
7
  from unittest.mock import MagicMock, patch
6
8
 
7
- import pytest
9
+ from typer.testing import CliRunner
8
10
 
11
+ from kctl_react.cli import app as cli_app
9
12
  from kctl_react.core.compliance.api_check.schema import Operation, ParsedSchema
10
13
  from kctl_react.core.compliance.api_health import EndpointResult, run_health_checks
11
14
  from kctl_react.core.compliance.api_health.checks import (
@@ -19,7 +22,6 @@ from kctl_react.core.compliance.api_health.checks import (
19
22
  from kctl_react.core.compliance.api_health.client import HealthClient
20
23
  from kctl_react.core.compliance.api_health.sampler import sample_endpoints
21
24
 
22
-
23
25
  # ---------------------------------------------------------------------------
24
26
  # Fixtures
25
27
  # ---------------------------------------------------------------------------
@@ -310,12 +312,6 @@ class TestRunHealthChecks:
310
312
  # CLI command tests (Typer CliRunner)
311
313
  # ---------------------------------------------------------------------------
312
314
 
313
- import json as _json
314
- from pathlib import Path
315
-
316
- from typer.testing import CliRunner
317
-
318
- from kctl_react.cli import app as cli_app
319
315
 
320
316
  _runner = CliRunner()
321
317
 
@@ -1289,10 +1289,17 @@ class TestUiPreset:
1289
1289
  .spinner { animation: spin 1s linear infinite; }
1290
1290
  """
1291
1291
  new_blocks = {
1292
- "@theme": " --color-primary: var(--primary);\n --color-background: var(--background);\n --radius-sm: calc(var(--radius) * 0.5);",
1292
+ "@theme": (
1293
+ " --color-primary: var(--primary);\n"
1294
+ " --color-background: var(--background);\n"
1295
+ " --radius-sm: calc(var(--radius) * 0.5);"
1296
+ ),
1293
1297
  ":root": " --primary: oklch(0.5 0.2 250);\n --background: oklch(1 0 0);\n --radius: 0.5rem;",
1294
1298
  ".dark": " --primary: oklch(0.8 0.2 250);\n --background: oklch(0.1 0 0);",
1295
- "@layer": " * {\n @apply border-border outline-ring/50;\n }\n body {\n @apply bg-background text-foreground;\n }",
1299
+ "@layer": (
1300
+ " * {\n @apply border-border outline-ring/50;\n }\n body {\n"
1301
+ " @apply bg-background text-foreground;\n }"
1302
+ ),
1296
1303
  }
1297
1304
 
1298
1305
  result = _build_updated_globals(old_globals, new_blocks)
@@ -2,14 +2,28 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import json as _json
5
6
  from pathlib import Path
6
7
  from unittest.mock import patch
7
8
 
8
- import pytest
9
+ from typer.testing import CliRunner
9
10
 
11
+ from kctl_react.cli import app as cli_app
12
+ from kctl_react.core.compliance.checks import ALL_CHECKERS, CHECKER_MAP
13
+ from kctl_react.core.compliance.checks.darkmode import DarkmodeChecker
14
+ from kctl_react.core.compliance.checks.errors import ErrorsChecker
15
+ from kctl_react.core.compliance.checks.i18n_check import I18nChecker
16
+ from kctl_react.core.compliance.checks.imports import ImportsChecker
17
+ from kctl_react.core.compliance.checks.providers import ProviderChecker
18
+ from kctl_react.core.compliance.checks.shadcn import ShadcnChecker
19
+ from kctl_react.core.compliance.checks.structure import REQUIRED_DIRS, StructureChecker
20
+ from kctl_react.core.compliance.checks.ui_standard import UiStandardChecker
10
21
  from kctl_react.core.compliance.engine import ComplianceEngine
11
22
  from kctl_react.core.compliance.exceptions_map import APP_EXCEPTIONS, get_skip_providers
12
23
  from kctl_react.core.compliance.fixes import apply_fixes
24
+ from kctl_react.core.compliance.fixes.i18n_fix import fix_i18n
25
+ from kctl_react.core.compliance.fixes.imports_fix import fix_imports
26
+ from kctl_react.core.compliance.fixes.structure_fix import fix_structure
13
27
  from kctl_react.core.compliance.models import (
14
28
  AppReport,
15
29
  CategoryResult,
@@ -17,7 +31,6 @@ from kctl_react.core.compliance.models import (
17
31
  compute_grade,
18
32
  )
19
33
 
20
-
21
34
  # ---------------------------------------------------------------------------
22
35
  # compute_grade
23
36
  # ---------------------------------------------------------------------------
@@ -159,7 +172,6 @@ class TestAppReport:
159
172
 
160
173
  def test_grade(self) -> None:
161
174
  r = self._make_report()
162
- pct = int(12 / 15 * 100) # 80 -> B
163
175
  assert r.grade == "B"
164
176
 
165
177
  def test_grade_empty_report(self) -> None:
@@ -348,15 +360,6 @@ class TestApplyFixes:
348
360
  # Checker imports
349
361
  # ---------------------------------------------------------------------------
350
362
 
351
- from kctl_react.core.compliance.checks import ALL_CHECKERS, CHECKER_MAP
352
- from kctl_react.core.compliance.checks.darkmode import DarkmodeChecker
353
- from kctl_react.core.compliance.checks.errors import ErrorsChecker
354
- from kctl_react.core.compliance.checks.i18n_check import I18nChecker
355
- from kctl_react.core.compliance.checks.imports import ImportsChecker
356
- from kctl_react.core.compliance.checks.providers import ProviderChecker
357
- from kctl_react.core.compliance.checks.shadcn import ShadcnChecker
358
- from kctl_react.core.compliance.checks.structure import StructureChecker
359
-
360
363
 
361
364
  # ---------------------------------------------------------------------------
362
365
  # Registry tests
@@ -738,9 +741,6 @@ class TestErrorsChecker:
738
741
  # Fixer: structure_fix
739
742
  # ---------------------------------------------------------------------------
740
743
 
741
- from kctl_react.core.compliance.fixes.structure_fix import fix_structure
742
- from kctl_react.core.compliance.checks.structure import REQUIRED_DIRS
743
-
744
744
 
745
745
  class TestFixStructure:
746
746
  def test_creates_missing_dirs(self, tmp_path: Path) -> None:
@@ -780,8 +780,6 @@ class TestFixStructure:
780
780
  # Fixer: imports_fix
781
781
  # ---------------------------------------------------------------------------
782
782
 
783
- from kctl_react.core.compliance.fixes.imports_fix import fix_imports
784
-
785
783
 
786
784
  class TestFixImports:
787
785
  def test_removes_use_client(self, tmp_path: Path) -> None:
@@ -843,8 +841,6 @@ class TestFixImports:
843
841
  # Fixer: i18n_fix
844
842
  # ---------------------------------------------------------------------------
845
843
 
846
- from kctl_react.core.compliance.fixes.i18n_fix import fix_i18n
847
-
848
844
 
849
845
  class TestFixI18n:
850
846
  def test_adds_missing_key_to_id(self, tmp_path: Path) -> None:
@@ -914,11 +910,6 @@ class TestFixI18n:
914
910
  # CLI command tests (Typer CliRunner)
915
911
  # ---------------------------------------------------------------------------
916
912
 
917
- import json as _json
918
-
919
- from typer.testing import CliRunner
920
-
921
- from kctl_react.cli import app as cli_app
922
913
 
923
914
  # ---------------------------------------------------------------------------
924
915
  # PracticesChecker — new checks
@@ -1098,8 +1089,6 @@ class TestCompliancePromptCLI:
1098
1089
  # UiStandardChecker
1099
1090
  # ---------------------------------------------------------------------------
1100
1091
 
1101
- from kctl_react.core.compliance.checks.ui_standard import UiStandardChecker
1102
-
1103
1092
 
1104
1093
  def _make_app(tmp_path: Path) -> Path:
1105
1094
  """Create a minimal app directory with required shared imports."""
@@ -1178,7 +1167,7 @@ class TestUiStandardChecker:
1178
1167
  app = _make_app(tmp_path)
1179
1168
  pages = app / "src" / "pages"
1180
1169
  for name in ("Orders.tsx", "Products.tsx", "Users.tsx"):
1181
- (pages / name).write_text(f"export function Page() {{ return <Table>data</Table>; }}\n")
1170
+ (pages / name).write_text("export function Page() { return <Table>data</Table>; }\n")
1182
1171
  checker = UiStandardChecker()
1183
1172
  result = checker.check(app, "myapp")
1184
1173
  msgs = [v.message for v in result.violations]
@@ -1188,7 +1177,7 @@ class TestUiStandardChecker:
1188
1177
  app = _make_app(tmp_path)
1189
1178
  pages = app / "src" / "pages"
1190
1179
  for name in ("Orders.tsx", "Products.tsx", "Users.tsx"):
1191
- (pages / name).write_text(f"export function Page() {{ return <Table>data</Table>; }}\n")
1180
+ (pages / name).write_text("export function Page() { return <Table>data</Table>; }\n")
1192
1181
  # Add DataTable import somewhere
1193
1182
  (app / "src" / "components" / "List.tsx").write_text(
1194
1183
  'import { DataTable } from "@kodemeio/ui";\nexport function List() { return <DataTable />; }\n'
File without changes
File without changes
File without changes
File without changes
@@ -14,8 +14,8 @@ from kctl_react.commands.build import app as build_app
14
14
  from kctl_react.commands.bundle_cmd import app as bundle_app
15
15
  from kctl_react.commands.cap import app as cap_app
16
16
  from kctl_react.commands.clean import app as clean_app
17
- from kctl_react.commands.compliance import app as compliance_app
18
17
  from kctl_react.commands.codegen import app as codegen_app
18
+ from kctl_react.commands.compliance import app as compliance_app
19
19
  from kctl_react.commands.config_cmd import app as config_app
20
20
  from kctl_react.commands.dashboard import app as dashboard_app
21
21
  from kctl_react.commands.deploy import app as deploy_app
@@ -14,8 +14,8 @@ from kctl_react.commands.clean import run_clean
14
14
  from kctl_react.commands.dashboard import _display_dashboard, _fetch_dashboard
15
15
  from kctl_react.commands.doctor import run_doctor
16
16
  from kctl_react.core.callbacks import AppContext
17
- from kctl_react.core.discovery import get_app_dir
18
17
  from kctl_react.core.config import resolve_active_profile_name
18
+ from kctl_react.core.discovery import get_app_dir
19
19
 
20
20
  app = typer.Typer(help="App inventory, status, and health checks.")
21
21
 
@@ -16,12 +16,12 @@ from kctl_react.core.runner import run_pnpm, run_turbo
16
16
 
17
17
  from ._helpers import (
18
18
  _ANDROID_CAP_PACKAGE,
19
+ _COMPILE_SDK,
19
20
  _DEFAULT_APP_ID_PREFIX,
20
21
  _IOS_CAP_PACKAGE,
21
22
  _MIN_ANDROID_SDK,
22
23
  _MIN_GRADLE_VERSION,
23
24
  _REQUIRED_CAP_PACKAGES,
24
- _COMPILE_SDK,
25
25
  _get_pkg_deps,
26
26
  _has_capacitor,
27
27
  _has_platform,