biucingcli 0.9.1__py3-none-any.whl

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 (269) hide show
  1. biucingcli/__init__.py +5 -0
  2. biucingcli/cli.py +849 -0
  3. biucingcli/template_data/android/template/.editorconfig +9 -0
  4. biucingcli/template_data/android/template/.gitignore +26 -0
  5. biucingcli/template_data/android/template/.mise.toml +3 -0
  6. biucingcli/template_data/android/template/Brewfile +6 -0
  7. biucingcli/template_data/android/template/Makefile +103 -0
  8. biucingcli/template_data/android/template/README.md +163 -0
  9. biucingcli/template_data/android/template/app/build.gradle.kts +178 -0
  10. biucingcli/template_data/android/template/app/proguard-rules.pro +1 -0
  11. biucingcli/template_data/android/template/app/src/androidTest/java/app/HomeRouteUiTest.kt +21 -0
  12. biucingcli/template_data/android/template/app/src/main/AndroidManifest.xml +18 -0
  13. biucingcli/template_data/android/template/app/src/main/java/app/MainActivity.kt +36 -0
  14. biucingcli/template_data/android/template/app/src/main/res/values/strings.xml +4 -0
  15. biucingcli/template_data/android/template/app/src/main/res/values/themes.xml +8 -0
  16. biucingcli/template_data/android/template/app/src/test/java/app/AppSmokeTest.kt +19 -0
  17. biucingcli/template_data/android/template/build.gradle.kts +27 -0
  18. biucingcli/template_data/android/template/core/designsystem/build.gradle.kts +33 -0
  19. biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Components.kt +75 -0
  20. biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/DesignTokens.kt +23 -0
  21. biucingcli/template_data/android/template/core/designsystem/src/main/java/designsystem/Theme.kt +110 -0
  22. biucingcli/template_data/android/template/core/model/build.gradle.kts +26 -0
  23. biucingcli/template_data/android/template/core/model/src/main/java/model/Greeting.kt +6 -0
  24. biucingcli/template_data/android/template/core/model/src/test/java/model/GreetingTest.kt +16 -0
  25. biucingcli/template_data/android/template/core/network/build.gradle.kts +26 -0
  26. biucingcli/template_data/android/template/core/network/src/main/java/network/AppEnvironment.kt +17 -0
  27. biucingcli/template_data/android/template/core/testing/build.gradle.kts +27 -0
  28. biucingcli/template_data/android/template/core/testing/src/main/java/testing/FakeAppEnvironmentProvider.kt +13 -0
  29. biucingcli/template_data/android/template/docs/release-delivery.md +68 -0
  30. biucingcli/template_data/android/template/docs/release-signing.properties.example +20 -0
  31. biucingcli/template_data/android/template/fastlane/.env.example +22 -0
  32. biucingcli/template_data/android/template/fastlane/Appfile +1 -0
  33. biucingcli/template_data/android/template/fastlane/Fastfile +121 -0
  34. biucingcli/template_data/android/template/feature/home/build.gradle.kts +35 -0
  35. biucingcli/template_data/android/template/feature/home/src/main/java/home/HomeRoute.kt +38 -0
  36. biucingcli/template_data/android/template/feature/settings/build.gradle.kts +34 -0
  37. biucingcli/template_data/android/template/feature/settings/src/main/java/settings/SettingsRoute.kt +35 -0
  38. biucingcli/template_data/android/template/gradle/libs.versions.toml +35 -0
  39. biucingcli/template_data/android/template/gradle/verification-metadata.xml +3462 -0
  40. biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar +0 -0
  41. biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.jar.sha256 +1 -0
  42. biucingcli/template_data/android/template/gradle/wrapper/gradle-wrapper.properties +10 -0
  43. biucingcli/template_data/android/template/gradle.properties +4 -0
  44. biucingcli/template_data/android/template/gradlew +252 -0
  45. biucingcli/template_data/android/template/gradlew.bat +94 -0
  46. biucingcli/template_data/android/template/scripts/artifact-info +11 -0
  47. biucingcli/template_data/android/template/scripts/bootstrap +17 -0
  48. biucingcli/template_data/android/template/scripts/doctor +133 -0
  49. biucingcli/template_data/android/template/scripts/setup-android-sdk +23 -0
  50. biucingcli/template_data/android/template/scripts/sync-gradle-wrapper +19 -0
  51. biucingcli/template_data/android/template/scripts/verify-gradle-supply-chain +61 -0
  52. biucingcli/template_data/android/template/scripts/verify-release-artifact +104 -0
  53. biucingcli/template_data/android/template/settings.gradle.kts +25 -0
  54. biucingcli/template_data/android/template.json +146 -0
  55. biucingcli/template_data/apple/template/.gitignore +28 -0
  56. biucingcli/template_data/apple/template/.mise.toml +4 -0
  57. biucingcli/template_data/apple/template/.swiftformat +10 -0
  58. biucingcli/template_data/apple/template/.swiftlint.yml +33 -0
  59. biucingcli/template_data/apple/template/App/Config/ProjectDescriptionHelpers/Module.swift +6 -0
  60. biucingcli/template_data/apple/template/App/Config/XCConfig/Base.xcconfig +4 -0
  61. biucingcli/template_data/apple/template/App/Project.swift +66 -0
  62. biucingcli/template_data/apple/template/App/Targets/App/Resources/.gitkeep +1 -0
  63. biucingcli/template_data/apple/template/App/Targets/App/Sources/AppEntry.swift +9 -0
  64. biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeView.swift +18 -0
  65. biucingcli/template_data/apple/template/App/Targets/App/Sources/HomeViewModel.swift +38 -0
  66. biucingcli/template_data/apple/template/App/Targets/AppTests/Sources/AppTests.swift +59 -0
  67. biucingcli/template_data/apple/template/Brewfile +8 -0
  68. biucingcli/template_data/apple/template/Makefile +128 -0
  69. biucingcli/template_data/apple/template/Packages/AppServices/Package.swift +20 -0
  70. biucingcli/template_data/apple/template/Packages/AppServices/Sources/AppServices/StarterMetadata.swift +52 -0
  71. biucingcli/template_data/apple/template/Packages/DesignSystem/Package.swift +20 -0
  72. biucingcli/template_data/apple/template/Packages/DesignSystem/Sources/DesignSystem/Theme.swift +8 -0
  73. biucingcli/template_data/apple/template/README.md +133 -0
  74. biucingcli/template_data/apple/template/Tuist.swift +8 -0
  75. biucingcli/template_data/apple/template/Workspace.swift +11 -0
  76. biucingcli/template_data/apple/template/docs/release-delivery.md +55 -0
  77. biucingcli/template_data/apple/template/fastlane/.env.example +20 -0
  78. biucingcli/template_data/apple/template/fastlane/Appfile +3 -0
  79. biucingcli/template_data/apple/template/fastlane/Fastfile +126 -0
  80. biucingcli/template_data/apple/template/fastlane/Matchfile +7 -0
  81. biucingcli/template_data/apple/template/scripts/bootstrap +9 -0
  82. biucingcli/template_data/apple/template/scripts/doctor +163 -0
  83. biucingcli/template_data/apple/template/scripts/setup-xcode +6 -0
  84. biucingcli/template_data/apple/template/scripts/test-destination +42 -0
  85. biucingcli/template_data/apple/template/scripts/verify-release-identity +88 -0
  86. biucingcli/template_data/apple/template.json +110 -0
  87. biucingcli/template_data/frontend/template/.dockerignore +8 -0
  88. biucingcli/template_data/frontend/template/.env.example +1 -0
  89. biucingcli/template_data/frontend/template/.gitignore +7 -0
  90. biucingcli/template_data/frontend/template/.npmrc +1 -0
  91. biucingcli/template_data/frontend/template/.prettierignore +2 -0
  92. biucingcli/template_data/frontend/template/.prettierrc.json +4 -0
  93. biucingcli/template_data/frontend/template/Dockerfile +25 -0
  94. biucingcli/template_data/frontend/template/Dockerfile.dev +35 -0
  95. biucingcli/template_data/frontend/template/Dockerfile.dev.full +40 -0
  96. biucingcli/template_data/frontend/template/Makefile +137 -0
  97. biucingcli/template_data/frontend/template/README.md +146 -0
  98. biucingcli/template_data/frontend/template/compose.dev.yaml +29 -0
  99. biucingcli/template_data/frontend/template/eslint.config.js +27 -0
  100. biucingcli/template_data/frontend/template/index.html +12 -0
  101. biucingcli/template_data/frontend/template/nginx.conf +11 -0
  102. biucingcli/template_data/frontend/template/package.json +50 -0
  103. biucingcli/template_data/frontend/template/playwright.production.config.ts +21 -0
  104. biucingcli/template_data/frontend/template/playwright.smoke.config.ts +19 -0
  105. biucingcli/template_data/frontend/template/pnpm-lock.yaml +4054 -0
  106. biucingcli/template_data/frontend/template/public/.gitkeep +1 -0
  107. biucingcli/template_data/frontend/template/scripts/browser-smoke-production +55 -0
  108. biucingcli/template_data/frontend/template/scripts/doctor +46 -0
  109. biucingcli/template_data/frontend/template/src/App.test.tsx +18 -0
  110. biucingcli/template_data/frontend/template/src/App.tsx +5 -0
  111. biucingcli/template_data/frontend/template/src/components/MetricCard.tsx +14 -0
  112. biucingcli/template_data/frontend/template/src/components/TaskPanel.tsx +32 -0
  113. biucingcli/template_data/frontend/template/src/config/env.ts +3 -0
  114. biucingcli/template_data/frontend/template/src/hooks/useProjectOverview.ts +24 -0
  115. biucingcli/template_data/frontend/template/src/index.css +208 -0
  116. biucingcli/template_data/frontend/template/src/main.tsx +11 -0
  117. biucingcli/template_data/frontend/template/src/pages/HomePage.tsx +60 -0
  118. biucingcli/template_data/frontend/template/src/router/AppRouter.tsx +14 -0
  119. biucingcli/template_data/frontend/template/src/services/api/client.ts +33 -0
  120. biucingcli/template_data/frontend/template/src/services/projectOverview.ts +39 -0
  121. biucingcli/template_data/frontend/template/src/test/setup.ts +1 -0
  122. biucingcli/template_data/frontend/template/src/types/projectOverview.ts +22 -0
  123. biucingcli/template_data/frontend/template/src/vite-env.d.ts +9 -0
  124. biucingcli/template_data/frontend/template/tests/browser-smoke.spec.ts +16 -0
  125. biucingcli/template_data/frontend/template/tests/production-browser-smoke.spec.ts +22 -0
  126. biucingcli/template_data/frontend/template/tsconfig.json +21 -0
  127. biucingcli/template_data/frontend/template/vite.config.ts +12 -0
  128. biucingcli/template_data/frontend/template.json +81 -0
  129. biucingcli/template_data/harmonyos/template/.gitignore +21 -0
  130. biucingcli/template_data/harmonyos/template/.mise.toml +2 -0
  131. biucingcli/template_data/harmonyos/template/AppScope/app.json5 +10 -0
  132. biucingcli/template_data/harmonyos/template/AppScope/resources/base/element/string.json +8 -0
  133. biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/background.svg +3 -0
  134. biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/foreground.svg +4 -0
  135. biucingcli/template_data/harmonyos/template/AppScope/resources/base/media/layered_image.json +6 -0
  136. biucingcli/template_data/harmonyos/template/Makefile +106 -0
  137. biucingcli/template_data/harmonyos/template/README.md +152 -0
  138. biucingcli/template_data/harmonyos/template/build-profile.json5 +36 -0
  139. biucingcli/template_data/harmonyos/template/code-linter.json5 +12 -0
  140. biucingcli/template_data/harmonyos/template/docs/release-signing.local.properties.example +14 -0
  141. biucingcli/template_data/harmonyos/template/entry/build-profile.json5 +9 -0
  142. biucingcli/template_data/harmonyos/template/entry/hvigorfile.ts +6 -0
  143. biucingcli/template_data/harmonyos/template/entry/oh-package.json5 +9 -0
  144. biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/config/AppConfig.ets +10 -0
  145. biucingcli/template_data/harmonyos/template/entry/src/main/ets/core/designsystem/Tokens.ets +28 -0
  146. biucingcli/template_data/harmonyos/template/entry/src/main/ets/entryability/EntryAbility.ets +29 -0
  147. biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Index.ets +47 -0
  148. biucingcli/template_data/harmonyos/template/entry/src/main/ets/pages/Settings.ets +96 -0
  149. biucingcli/template_data/harmonyos/template/entry/src/main/module.json5 +34 -0
  150. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/color.json +24 -0
  151. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/element/string.json +12 -0
  152. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/media/app_icon.svg +5 -0
  153. biucingcli/template_data/harmonyos/template/entry/src/main/resources/base/profile/main_pages.json +6 -0
  154. biucingcli/template_data/harmonyos/template/entry/src/test/List.test.ets +11 -0
  155. biucingcli/template_data/harmonyos/template/hvigor/hvigor-config.json5 +8 -0
  156. biucingcli/template_data/harmonyos/template/hvigorfile.ts +6 -0
  157. biucingcli/template_data/harmonyos/template/oh-package-lock.json5 +19 -0
  158. biucingcli/template_data/harmonyos/template/oh-package.json5 +13 -0
  159. biucingcli/template_data/harmonyos/template/scripts/artifact-info +31 -0
  160. biucingcli/template_data/harmonyos/template/scripts/bootstrap +38 -0
  161. biucingcli/template_data/harmonyos/template/scripts/doctor +147 -0
  162. biucingcli/template_data/harmonyos/template/scripts/lint +105 -0
  163. biucingcli/template_data/harmonyos/template/scripts/release-build +199 -0
  164. biucingcli/template_data/harmonyos/template/scripts/release-preflight +109 -0
  165. biucingcli/template_data/harmonyos/template/scripts/test +28 -0
  166. biucingcli/template_data/harmonyos/template/scripts/verify-release-artifact +173 -0
  167. biucingcli/template_data/harmonyos/template/scripts/verify-supply-chain +70 -0
  168. biucingcli/template_data/harmonyos/template.json +134 -0
  169. biucingcli/template_data/microservice/template/.air.toml +11 -0
  170. biucingcli/template_data/microservice/template/.dockerignore +5 -0
  171. biucingcli/template_data/microservice/template/.gitignore +4 -0
  172. biucingcli/template_data/microservice/template/.mise.toml +3 -0
  173. biucingcli/template_data/microservice/template/Brewfile +7 -0
  174. biucingcli/template_data/microservice/template/Dockerfile +44 -0
  175. biucingcli/template_data/microservice/template/Dockerfile.dev +50 -0
  176. biucingcli/template_data/microservice/template/Makefile +145 -0
  177. biucingcli/template_data/microservice/template/README.md +191 -0
  178. biucingcli/template_data/microservice/template/api/buf.gen.yaml +11 -0
  179. biucingcli/template_data/microservice/template/api/buf.yaml +11 -0
  180. biucingcli/template_data/microservice/template/api/proto/service/v1/service.proto +18 -0
  181. biucingcli/template_data/microservice/template/cmd/server/main.go +81 -0
  182. biucingcli/template_data/microservice/template/compose.dev.yaml +49 -0
  183. biucingcli/template_data/microservice/template/configs/config.yaml +18 -0
  184. biucingcli/template_data/microservice/template/deploy/compose.yaml +35 -0
  185. biucingcli/template_data/microservice/template/deploy/otel-collector.yaml +15 -0
  186. biucingcli/template_data/microservice/template/go.mod +53 -0
  187. biucingcli/template_data/microservice/template/go.sum +138 -0
  188. biucingcli/template_data/microservice/template/internal/config/config.go +112 -0
  189. biucingcli/template_data/microservice/template/internal/config/config_test.go +92 -0
  190. biucingcli/template_data/microservice/template/internal/handler/health.go +25 -0
  191. biucingcli/template_data/microservice/template/internal/handler/ping.go +25 -0
  192. biucingcli/template_data/microservice/template/internal/model/health.go +8 -0
  193. biucingcli/template_data/microservice/template/internal/model/ping.go +7 -0
  194. biucingcli/template_data/microservice/template/internal/repository/.gitkeep +1 -0
  195. biucingcli/template_data/microservice/template/internal/router/router.go +26 -0
  196. biucingcli/template_data/microservice/template/internal/runtime/server.go +116 -0
  197. biucingcli/template_data/microservice/template/internal/runtime/server_test.go +161 -0
  198. biucingcli/template_data/microservice/template/internal/service/health.go +26 -0
  199. biucingcli/template_data/microservice/template/internal/service/ping.go +23 -0
  200. biucingcli/template_data/microservice/template/internal/telemetry/telemetry.go +56 -0
  201. biucingcli/template_data/microservice/template/internal/transport/grpc.go +51 -0
  202. biucingcli/template_data/microservice/template/internal/transport/ping.go +28 -0
  203. biucingcli/template_data/microservice/template/scripts/bootstrap +29 -0
  204. biucingcli/template_data/microservice/template/scripts/doctor +115 -0
  205. biucingcli/template_data/microservice/template/tests/server_test.go +153 -0
  206. biucingcli/template_data/microservice/template.json +114 -0
  207. biucingcli/template_data/web-service/template/.air.toml +11 -0
  208. biucingcli/template_data/web-service/template/.dockerignore +5 -0
  209. biucingcli/template_data/web-service/template/.gitignore +5 -0
  210. biucingcli/template_data/web-service/template/.mise.toml +2 -0
  211. biucingcli/template_data/web-service/template/Brewfile +5 -0
  212. biucingcli/template_data/web-service/template/Dockerfile +41 -0
  213. biucingcli/template_data/web-service/template/Dockerfile.dev +45 -0
  214. biucingcli/template_data/web-service/template/Makefile +113 -0
  215. biucingcli/template_data/web-service/template/README.md +164 -0
  216. biucingcli/template_data/web-service/template/cmd/server/main.go +50 -0
  217. biucingcli/template_data/web-service/template/compose.dev.yaml +28 -0
  218. biucingcli/template_data/web-service/template/compose.yaml +14 -0
  219. biucingcli/template_data/web-service/template/configs/config.yaml +10 -0
  220. biucingcli/template_data/web-service/template/go.mod +36 -0
  221. biucingcli/template_data/web-service/template/go.sum +89 -0
  222. biucingcli/template_data/web-service/template/internal/config/config.go +84 -0
  223. biucingcli/template_data/web-service/template/internal/config/config_test.go +88 -0
  224. biucingcli/template_data/web-service/template/internal/handler/health.go +25 -0
  225. biucingcli/template_data/web-service/template/internal/handler/ping.go +25 -0
  226. biucingcli/template_data/web-service/template/internal/handler/user.go +40 -0
  227. biucingcli/template_data/web-service/template/internal/model/health.go +6 -0
  228. biucingcli/template_data/web-service/template/internal/model/ping.go +7 -0
  229. biucingcli/template_data/web-service/template/internal/model/user.go +7 -0
  230. biucingcli/template_data/web-service/template/internal/repository/.gitkeep +1 -0
  231. biucingcli/template_data/web-service/template/internal/repository/user.go +37 -0
  232. biucingcli/template_data/web-service/template/internal/router/router.go +28 -0
  233. biucingcli/template_data/web-service/template/internal/runtime/server.go +76 -0
  234. biucingcli/template_data/web-service/template/internal/runtime/server_test.go +139 -0
  235. biucingcli/template_data/web-service/template/internal/service/health.go +22 -0
  236. biucingcli/template_data/web-service/template/internal/service/ping.go +23 -0
  237. biucingcli/template_data/web-service/template/internal/service/user.go +27 -0
  238. biucingcli/template_data/web-service/template/scripts/bootstrap +23 -0
  239. biucingcli/template_data/web-service/template/scripts/doctor +83 -0
  240. biucingcli/template_data/web-service/template/tests/server_test.go +160 -0
  241. biucingcli/template_data/web-service/template.json +88 -0
  242. biucingcli/template_data/worker/template/.dockerignore +3 -0
  243. biucingcli/template_data/worker/template/.gitignore +2 -0
  244. biucingcli/template_data/worker/template/.mise.toml +2 -0
  245. biucingcli/template_data/worker/template/Brewfile +1 -0
  246. biucingcli/template_data/worker/template/Dockerfile +19 -0
  247. biucingcli/template_data/worker/template/Dockerfile.dev +9 -0
  248. biucingcli/template_data/worker/template/Makefile +105 -0
  249. biucingcli/template_data/worker/template/README.md +164 -0
  250. biucingcli/template_data/worker/template/cmd/worker/main.go +41 -0
  251. biucingcli/template_data/worker/template/compose.dev.yaml +29 -0
  252. biucingcli/template_data/worker/template/configs/config.json +11 -0
  253. biucingcli/template_data/worker/template/go.mod +3 -0
  254. biucingcli/template_data/worker/template/go.sum +1 -0
  255. biucingcli/template_data/worker/template/internal/config/config.go +108 -0
  256. biucingcli/template_data/worker/template/internal/config/config_test.go +86 -0
  257. biucingcli/template_data/worker/template/internal/runtime/runner.go +199 -0
  258. biucingcli/template_data/worker/template/internal/runtime/runner_test.go +215 -0
  259. biucingcli/template_data/worker/template/internal/task/heartbeat.go +19 -0
  260. biucingcli/template_data/worker/template/scripts/bootstrap +6 -0
  261. biucingcli/template_data/worker/template/scripts/doctor +41 -0
  262. biucingcli/template_data/worker/template/tests/worker_test.go +44 -0
  263. biucingcli/template_data/worker/template.json +100 -0
  264. biucingcli/templates.py +902 -0
  265. biucingcli-0.9.1.dist-info/METADATA +204 -0
  266. biucingcli-0.9.1.dist-info/RECORD +269 -0
  267. biucingcli-0.9.1.dist-info/WHEEL +5 -0
  268. biucingcli-0.9.1.dist-info/entry_points.txt +2 -0
  269. biucingcli-0.9.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ DOCKER_BIN="${DOCKER:-docker}"
5
+ IMAGE_REF="${IMAGE_REF:?IMAGE_REF is required}"
6
+ HOST_PORT="${HOST_PORT:-8080}"
7
+ CONTAINER_PORT="${CONTAINER_PORT:-80}"
8
+ RUNTIME_CONTAINER="${RUNTIME_CONTAINER:?RUNTIME_CONTAINER is required}"
9
+ DEV_COMPOSE_FILE="${DEV_COMPOSE_FILE:-compose.dev.yaml}"
10
+ DEV_SERVICE="${DEV_SERVICE:-frontend-dev}"
11
+ DEV_DOCKERFILE="${DEV_DOCKERFILE:-Dockerfile.dev}"
12
+ COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:?COMPOSE_PROJECT_NAME is required}"
13
+ container_started=false
14
+
15
+ cleanup() {
16
+ if [[ "$container_started" == "true" ]]; then
17
+ "$DOCKER_BIN" rm -f "$RUNTIME_CONTAINER" >/dev/null 2>&1 || true
18
+ fi
19
+ }
20
+ trap cleanup EXIT
21
+ trap 'exit 129' HUP
22
+ trap 'exit 130' INT
23
+ trap 'exit 143' TERM
24
+
25
+ "$DOCKER_BIN" run --detach \
26
+ --name "$RUNTIME_CONTAINER" \
27
+ --publish "127.0.0.1:${HOST_PORT}:${CONTAINER_PORT}" \
28
+ "$IMAGE_REF" >/dev/null
29
+ container_started=true
30
+
31
+ runtime_status=""
32
+ for _ in $(seq 1 30); do
33
+ runtime_status="$("$DOCKER_BIN" inspect --format '{{.State.Health.Status}}' "$RUNTIME_CONTAINER")"
34
+ if [[ "$runtime_status" == "healthy" ]]; then
35
+ break
36
+ fi
37
+ if [[ "$runtime_status" == "unhealthy" ]]; then
38
+ break
39
+ fi
40
+ sleep 1
41
+ done
42
+
43
+ if [[ "$runtime_status" != "healthy" ]]; then
44
+ echo "Production container did not become healthy (status: ${runtime_status:-unknown})." >&2
45
+ "$DOCKER_BIN" logs "$RUNTIME_CONTAINER" >&2 || true
46
+ exit 1
47
+ fi
48
+
49
+ PLAYWRIGHT_BASE_URL="http://host.docker.internal:${HOST_PORT}" \
50
+ DEV_DOCKERFILE="$DEV_DOCKERFILE" \
51
+ COMPOSE_PROJECT_NAME="$COMPOSE_PROJECT_NAME" \
52
+ "$DOCKER_BIN" compose -f "$DEV_COMPOSE_FILE" run --rm \
53
+ --env PLAYWRIGHT_BASE_URL \
54
+ "$DEV_SERVICE" \
55
+ pnpm browser:smoke:production
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ echo "Frontend environment doctor"
5
+
6
+ failures=0
7
+ fail() {
8
+ echo "[fail] $1" >&2
9
+ failures=$((failures + 1))
10
+ }
11
+ pass() {
12
+ echo "[pass] $1"
13
+ }
14
+
15
+ if command -v docker >/dev/null 2>&1; then
16
+ pass "docker is available"
17
+ if docker compose version >/dev/null 2>&1; then
18
+ pass "docker compose is available"
19
+ else
20
+ fail "docker compose is unavailable"
21
+ fi
22
+ else
23
+ fail "docker is unavailable"
24
+ fi
25
+
26
+ for path in package.json pnpm-lock.yaml Dockerfile Dockerfile.dev compose.dev.yaml; do
27
+ if [[ -f "$path" ]]; then
28
+ pass "$path exists"
29
+ else
30
+ fail "$path is missing"
31
+ fi
32
+ done
33
+
34
+ if grep -q '"packageManager": "pnpm@9.9.0"' package.json && \
35
+ grep -q "lockfileVersion: '9.0'" pnpm-lock.yaml; then
36
+ pass "package manager and lockfile versions agree"
37
+ else
38
+ fail "package.json and pnpm-lock.yaml must keep the pinned pnpm 9 contract"
39
+ fi
40
+
41
+ if (( failures > 0 )); then
42
+ echo "Doctor found ${failures} issue(s)." >&2
43
+ exit 1
44
+ fi
45
+
46
+ echo "Environment looks ready."
@@ -0,0 +1,18 @@
1
+ import { render, screen } from "@testing-library/react";
2
+ import { describe, expect, it } from "vitest";
3
+
4
+ import App from "./App";
5
+ import { getProjectOverview } from "./services/projectOverview";
6
+
7
+ describe("App", () => {
8
+ it("renders the project overview content", async () => {
9
+ const overview = await getProjectOverview();
10
+
11
+ render(<App />);
12
+
13
+ expect(await screen.findByRole("heading", { name: overview.title })).toBeInTheDocument();
14
+ expect(screen.getByText(overview.description)).toBeInTheDocument();
15
+ expect(screen.getByText("Build Queue")).toBeInTheDocument();
16
+ expect(screen.getByText("Project Notes")).toBeInTheDocument();
17
+ });
18
+ });
@@ -0,0 +1,5 @@
1
+ import { AppRouter } from "./router/AppRouter";
2
+
3
+ export default function App() {
4
+ return <AppRouter />;
5
+ }
@@ -0,0 +1,14 @@
1
+ type MetricCardProps = {
2
+ label: string;
3
+ value: string;
4
+ tone: "amber" | "slate";
5
+ };
6
+
7
+ export function MetricCard({ label, value, tone }: MetricCardProps) {
8
+ return (
9
+ <article className={`metric-card metric-card--${tone}`}>
10
+ <p className="metric-card__label">{label}</p>
11
+ <p className="metric-card__value">{value}</p>
12
+ </article>
13
+ );
14
+ }
@@ -0,0 +1,32 @@
1
+ type Task = {
2
+ id: string;
3
+ title: string;
4
+ status: string;
5
+ };
6
+
7
+ type TaskPanelProps = {
8
+ title: string;
9
+ tasks: Task[];
10
+ };
11
+
12
+ export function TaskPanel({ title, tasks }: TaskPanelProps) {
13
+ return (
14
+ <section className="panel">
15
+ <div className="panel__header">
16
+ <h2>{title}</h2>
17
+ <span>{tasks.length} items</span>
18
+ </div>
19
+ <div className="task-list">
20
+ {tasks.map((task) => (
21
+ <article className="task-row" key={task.id}>
22
+ <div>
23
+ <strong>{task.title}</strong>
24
+ <p>{task.id}</p>
25
+ </div>
26
+ <span className="task-row__status">{task.status}</span>
27
+ </article>
28
+ ))}
29
+ </div>
30
+ </section>
31
+ );
32
+ }
@@ -0,0 +1,3 @@
1
+ export const env = {
2
+ apiBaseUrl: import.meta.env.VITE_API_BASE_URL?.trim() ?? "",
3
+ };
@@ -0,0 +1,24 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ import { getProjectOverview } from "../services/projectOverview";
4
+ import type { ProjectOverview } from "../types/projectOverview";
5
+
6
+ export function useProjectOverview() {
7
+ const [overview, setOverview] = useState<ProjectOverview | null>(null);
8
+
9
+ useEffect(() => {
10
+ let isMounted = true;
11
+
12
+ void getProjectOverview().then((data) => {
13
+ if (isMounted) {
14
+ setOverview(data);
15
+ }
16
+ });
17
+
18
+ return () => {
19
+ isMounted = false;
20
+ };
21
+ }, []);
22
+
23
+ return overview;
24
+ }
@@ -0,0 +1,208 @@
1
+ :root {
2
+ font-family: "Avenir Next", "Helvetica Neue", Helvetica, Arial, sans-serif;
3
+ line-height: 1.5;
4
+ font-weight: 400;
5
+ color: #1f2937;
6
+ background:
7
+ radial-gradient(circle at top left, rgba(242, 186, 97, 0.3), transparent 30%),
8
+ linear-gradient(180deg, #f4efe6 0%, #fffdf8 100%);
9
+ }
10
+
11
+ * {
12
+ box-sizing: border-box;
13
+ }
14
+
15
+ body {
16
+ margin: 0;
17
+ min-width: 320px;
18
+ min-height: 100vh;
19
+ }
20
+
21
+ #root {
22
+ min-height: 100vh;
23
+ }
24
+
25
+ .app-shell {
26
+ min-height: 100vh;
27
+ padding: 32px;
28
+ }
29
+
30
+ .workspace {
31
+ width: min(1120px, 100%);
32
+ margin: 0 auto;
33
+ display: grid;
34
+ gap: 24px;
35
+ }
36
+
37
+ .hero {
38
+ display: grid;
39
+ gap: 16px;
40
+ padding: 28px;
41
+ border: 1px solid rgba(73, 55, 32, 0.12);
42
+ border-radius: 8px;
43
+ background: rgba(255, 251, 244, 0.8);
44
+ backdrop-filter: blur(8px);
45
+ }
46
+
47
+ .hero__eyebrow {
48
+ margin: 0;
49
+ text-transform: uppercase;
50
+ font-size: 12px;
51
+ color: #8c5a13;
52
+ }
53
+
54
+ .hero__headline {
55
+ margin: 0;
56
+ display: grid;
57
+ gap: 8px;
58
+ }
59
+
60
+ .hero__headline h1 {
61
+ margin: 0;
62
+ font-size: clamp(36px, 6vw, 64px);
63
+ line-height: 1;
64
+ }
65
+
66
+ .hero__headline p {
67
+ margin: 0;
68
+ max-width: 56ch;
69
+ font-size: 18px;
70
+ }
71
+
72
+ .hero__meta {
73
+ display: flex;
74
+ flex-wrap: wrap;
75
+ gap: 12px;
76
+ }
77
+
78
+ .hero__tag {
79
+ padding: 10px 14px;
80
+ border-radius: 999px;
81
+ background: #fff5e4;
82
+ color: #6a4310;
83
+ font-size: 14px;
84
+ }
85
+
86
+ .metrics {
87
+ display: grid;
88
+ grid-template-columns: repeat(3, minmax(0, 1fr));
89
+ gap: 16px;
90
+ }
91
+
92
+ .metric-card {
93
+ padding: 20px;
94
+ border-radius: 8px;
95
+ border: 1px solid rgba(31, 41, 55, 0.1);
96
+ background: rgba(255, 255, 255, 0.92);
97
+ }
98
+
99
+ .metric-card--amber {
100
+ background: #fff7ea;
101
+ }
102
+
103
+ .metric-card__label {
104
+ margin: 0 0 12px;
105
+ font-size: 13px;
106
+ color: #6b7280;
107
+ }
108
+
109
+ .metric-card__value {
110
+ margin: 0;
111
+ font-size: 28px;
112
+ font-weight: 600;
113
+ }
114
+
115
+ .panels {
116
+ display: grid;
117
+ grid-template-columns: 1.3fr 1fr;
118
+ gap: 16px;
119
+ }
120
+
121
+ .panel {
122
+ padding: 20px;
123
+ border-radius: 8px;
124
+ border: 1px solid rgba(31, 41, 55, 0.1);
125
+ background: rgba(255, 255, 255, 0.92);
126
+ }
127
+
128
+ .panel__header {
129
+ display: flex;
130
+ align-items: baseline;
131
+ justify-content: space-between;
132
+ gap: 16px;
133
+ margin-bottom: 16px;
134
+ }
135
+
136
+ .panel__header h2 {
137
+ margin: 0;
138
+ font-size: 20px;
139
+ }
140
+
141
+ .panel__header span {
142
+ font-size: 13px;
143
+ color: #6b7280;
144
+ }
145
+
146
+ .task-list {
147
+ display: grid;
148
+ gap: 12px;
149
+ }
150
+
151
+ .task-row {
152
+ display: flex;
153
+ align-items: center;
154
+ justify-content: space-between;
155
+ gap: 16px;
156
+ padding: 14px 0;
157
+ border-top: 1px solid rgba(31, 41, 55, 0.08);
158
+ }
159
+
160
+ .task-row:first-child {
161
+ border-top: 0;
162
+ padding-top: 0;
163
+ }
164
+
165
+ .task-row strong,
166
+ .task-row p {
167
+ display: block;
168
+ }
169
+
170
+ .task-row strong {
171
+ margin-bottom: 4px;
172
+ }
173
+
174
+ .task-row p {
175
+ margin: 0;
176
+ color: #6b7280;
177
+ font-size: 13px;
178
+ }
179
+
180
+ .task-row__status {
181
+ white-space: nowrap;
182
+ color: #8c5a13;
183
+ background: #fff5e4;
184
+ border-radius: 999px;
185
+ padding: 8px 12px;
186
+ font-size: 13px;
187
+ }
188
+
189
+ @media (max-width: 900px) {
190
+ .metrics,
191
+ .panels {
192
+ grid-template-columns: 1fr;
193
+ }
194
+ }
195
+
196
+ @media (max-width: 640px) {
197
+ .app-shell {
198
+ padding: 20px;
199
+ }
200
+
201
+ .hero {
202
+ padding: 20px;
203
+ }
204
+
205
+ .hero__headline h1 {
206
+ font-size: 40px;
207
+ }
208
+ }
@@ -0,0 +1,11 @@
1
+ import React from "react";
2
+ import ReactDOM from "react-dom/client";
3
+
4
+ import App from "./App";
5
+ import "./index.css";
6
+
7
+ ReactDOM.createRoot(document.getElementById("root")!).render(
8
+ <React.StrictMode>
9
+ <App />
10
+ </React.StrictMode>,
11
+ );
@@ -0,0 +1,60 @@
1
+ import { MetricCard } from "../components/MetricCard";
2
+ import { TaskPanel } from "../components/TaskPanel";
3
+ import { useProjectOverview } from "../hooks/useProjectOverview";
4
+
5
+ export function HomePage() {
6
+ const overview = useProjectOverview();
7
+
8
+ if (!overview) {
9
+ return (
10
+ <main className="app-shell">
11
+ <div className="workspace">
12
+ <section className="hero">
13
+ <p className="hero__eyebrow">BiucingCLI</p>
14
+ <div className="hero__headline">
15
+ <h1>{{DISPLAY_NAME}}</h1>
16
+ <p>Loading your starter workspace...</p>
17
+ </div>
18
+ </section>
19
+ </div>
20
+ </main>
21
+ );
22
+ }
23
+
24
+ return (
25
+ <main className="app-shell">
26
+ <div className="workspace">
27
+ <section className="hero">
28
+ <p className="hero__eyebrow">BiucingCLI</p>
29
+ <div className="hero__headline">
30
+ <h1>{overview.title}</h1>
31
+ <p>{overview.description}</p>
32
+ </div>
33
+ <div className="hero__meta">
34
+ {overview.tags.map((tag) => (
35
+ <span className="hero__tag" key={tag}>
36
+ {tag}
37
+ </span>
38
+ ))}
39
+ </div>
40
+ </section>
41
+
42
+ <section className="metrics">
43
+ {overview.metrics.map((metric) => (
44
+ <MetricCard
45
+ key={metric.label}
46
+ label={metric.label}
47
+ value={metric.value}
48
+ tone={metric.tone}
49
+ />
50
+ ))}
51
+ </section>
52
+
53
+ <section className="panels">
54
+ <TaskPanel title="Build Queue" tasks={overview.buildQueue} />
55
+ <TaskPanel title="Project Notes" tasks={overview.notes} />
56
+ </section>
57
+ </div>
58
+ </main>
59
+ );
60
+ }
@@ -0,0 +1,14 @@
1
+ import { createBrowserRouter, RouterProvider } from "react-router-dom";
2
+
3
+ import { HomePage } from "../pages/HomePage";
4
+
5
+ const router = createBrowserRouter([
6
+ {
7
+ path: "/",
8
+ element: <HomePage />,
9
+ },
10
+ ]);
11
+
12
+ export function AppRouter() {
13
+ return <RouterProvider router={router} future={{ v7_startTransition: true }} />;
14
+ }
@@ -0,0 +1,33 @@
1
+ import { env } from "../../config/env";
2
+
3
+ export class ApiError extends Error {
4
+ constructor(
5
+ message: string,
6
+ public readonly status: number,
7
+ ) {
8
+ super(message);
9
+ this.name = "ApiError";
10
+ }
11
+ }
12
+
13
+ function buildUrl(path: string): string {
14
+ if (!env.apiBaseUrl) {
15
+ throw new Error("VITE_API_BASE_URL is not configured");
16
+ }
17
+
18
+ return new URL(path, `${env.apiBaseUrl.replace(/\/+$/, "")}/`).toString();
19
+ }
20
+
21
+ export async function getJson<T>(path: string): Promise<T> {
22
+ const response = await fetch(buildUrl(path), {
23
+ headers: {
24
+ Accept: "application/json",
25
+ },
26
+ });
27
+
28
+ if (!response.ok) {
29
+ throw new ApiError(`Request failed for ${path}`, response.status);
30
+ }
31
+
32
+ return (await response.json()) as T;
33
+ }
@@ -0,0 +1,39 @@
1
+ import { env } from "../config/env";
2
+ import { getJson } from "./api/client";
3
+ import type { ProjectOverview } from "../types/projectOverview";
4
+
5
+ export function getProjectOverviewFallback(): ProjectOverview {
6
+ return {
7
+ title: "{{DISPLAY_NAME}}",
8
+ description:
9
+ "A practical React + TypeScript starter with a small UI structure, a lightweight service layer, and room to grow without cleanup first.",
10
+ tags: ["React", "TypeScript", "Vite", "BiucingCLI"],
11
+ metrics: [
12
+ { label: "Screens ready", value: "1", tone: "amber" },
13
+ { label: "Shared services", value: "1", tone: "slate" },
14
+ { label: "UI building blocks", value: "2", tone: "slate" },
15
+ ],
16
+ buildQueue: [
17
+ { id: "task_01", title: "Replace starter copy with product copy", status: "Ready" },
18
+ { id: "task_02", title: "Connect API requests in services layer", status: "Planned" },
19
+ { id: "task_03", title: "Split HomePage into route-level screens", status: "Backlog" },
20
+ ],
21
+ notes: [
22
+ { id: "note_01", title: "Start with pages as feature entrypoints", status: "Pattern" },
23
+ { id: "note_02", title: "Keep API logic inside services", status: "Pattern" },
24
+ { id: "note_03", title: "Promote components only when reused", status: "Reminder" },
25
+ ],
26
+ };
27
+ }
28
+
29
+ export async function getProjectOverview(): Promise<ProjectOverview> {
30
+ if (!env.apiBaseUrl) {
31
+ return getProjectOverviewFallback();
32
+ }
33
+
34
+ try {
35
+ return await getJson<ProjectOverview>("/project-overview");
36
+ } catch {
37
+ return getProjectOverviewFallback();
38
+ }
39
+ }
@@ -0,0 +1 @@
1
+ import "@testing-library/jest-dom/vitest";
@@ -0,0 +1,22 @@
1
+ export type MetricTone = "amber" | "slate";
2
+
3
+ export type ProjectTask = {
4
+ id: string;
5
+ title: string;
6
+ status: string;
7
+ };
8
+
9
+ export type ProjectMetric = {
10
+ label: string;
11
+ value: string;
12
+ tone: MetricTone;
13
+ };
14
+
15
+ export type ProjectOverview = {
16
+ title: string;
17
+ description: string;
18
+ tags: string[];
19
+ metrics: ProjectMetric[];
20
+ buildQueue: ProjectTask[];
21
+ notes: ProjectTask[];
22
+ };
@@ -0,0 +1,9 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ interface ImportMetaEnv {
4
+ readonly VITE_API_BASE_URL?: string;
5
+ }
6
+
7
+ interface ImportMeta {
8
+ readonly env: ImportMetaEnv;
9
+ }
@@ -0,0 +1,16 @@
1
+ import { expect, test } from "playwright/test";
2
+
3
+ test("starter homepage renders key sections", async ({ page }, testInfo) => {
4
+ await page.goto("/");
5
+
6
+ await expect(page).toHaveTitle(/{{DISPLAY_NAME}}/);
7
+ await expect(page.getByRole("heading", { name: "{{DISPLAY_NAME}}" })).toBeVisible();
8
+ await expect(page.getByText("Build Queue")).toBeVisible();
9
+ await expect(page.getByText("Project Notes")).toBeVisible();
10
+ await expect(page.locator(".metric-card")).toHaveCount(3);
11
+
12
+ await page.screenshot({
13
+ path: testInfo.outputPath("browser-smoke-homepage.png"),
14
+ fullPage: true,
15
+ });
16
+ });
@@ -0,0 +1,22 @@
1
+ import { expect, test } from "playwright/test";
2
+
3
+ test("production image serves the starter through nginx", async ({
4
+ page,
5
+ }, testInfo) => {
6
+ const response = await page.goto("/");
7
+
8
+ expect(response?.ok()).toBe(true);
9
+ expect(response?.headers()["server"]).toContain("nginx");
10
+ await expect(page).toHaveTitle(/{{DISPLAY_NAME}}/);
11
+ await expect(
12
+ page.getByRole("heading", { name: "{{DISPLAY_NAME}}" }),
13
+ ).toBeVisible();
14
+ await expect(page.getByText("Build Queue")).toBeVisible();
15
+ await expect(page.getByText("Project Notes")).toBeVisible();
16
+ await expect(page.locator(".metric-card")).toHaveCount(3);
17
+
18
+ await page.screenshot({
19
+ path: testInfo.outputPath("production-image-homepage.png"),
20
+ fullPage: true,
21
+ });
22
+ });
@@ -0,0 +1,21 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "useDefineForClassFields": true,
5
+ "lib": ["DOM", "DOM.Iterable", "ES2020"],
6
+ "allowJs": false,
7
+ "skipLibCheck": true,
8
+ "esModuleInterop": true,
9
+ "allowSyntheticDefaultImports": true,
10
+ "strict": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "module": "ESNext",
13
+ "moduleResolution": "Node",
14
+ "resolveJsonModule": true,
15
+ "isolatedModules": true,
16
+ "noEmit": true,
17
+ "jsx": "react-jsx"
18
+ },
19
+ "include": ["src"],
20
+ "references": []
21
+ }