groundwork-method 0.0.1 → 0.11.0

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 (647) hide show
  1. package/CHANGELOG.md +823 -0
  2. package/LICENSE +21 -0
  3. package/README.md +44 -29
  4. package/bin/groundwork.js +1723 -0
  5. package/dist/src/generators/add-capability/generator.d.ts +8 -0
  6. package/dist/src/generators/add-capability/generator.js +60 -0
  7. package/dist/src/generators/add-capability/generator.js.map +1 -0
  8. package/dist/src/generators/cli-app/generator.d.ts +9 -0
  9. package/dist/src/generators/cli-app/generator.js +140 -0
  10. package/dist/src/generators/cli-app/generator.js.map +1 -0
  11. package/dist/src/generators/docs-site/generator.d.ts +5 -0
  12. package/dist/src/generators/docs-site/generator.js +441 -0
  13. package/dist/src/generators/docs-site/generator.js.map +1 -0
  14. package/dist/src/generators/electron-app/generator.d.ts +6 -0
  15. package/dist/src/generators/electron-app/generator.js +261 -0
  16. package/dist/src/generators/electron-app/generator.js.map +1 -0
  17. package/dist/src/generators/flutter-app/generator.d.ts +6 -0
  18. package/dist/src/generators/flutter-app/generator.js +314 -0
  19. package/dist/src/generators/flutter-app/generator.js.map +1 -0
  20. package/dist/src/generators/go-microservice/generator.d.ts +8 -0
  21. package/dist/src/generators/go-microservice/generator.js +232 -0
  22. package/dist/src/generators/go-microservice/generator.js.map +1 -0
  23. package/dist/src/generators/nextjs-app/generator.d.ts +8 -0
  24. package/dist/src/generators/nextjs-app/generator.js +294 -0
  25. package/dist/src/generators/nextjs-app/generator.js.map +1 -0
  26. package/dist/src/generators/python-microservice/generator.d.ts +13 -0
  27. package/dist/src/generators/python-microservice/generator.js +265 -0
  28. package/dist/src/generators/python-microservice/generator.js.map +1 -0
  29. package/dist/src/generators/shared/brand-tokens.d.ts +89 -0
  30. package/dist/src/generators/shared/brand-tokens.js +308 -0
  31. package/dist/src/generators/shared/brand-tokens.js.map +1 -0
  32. package/dist/src/generators/shared/capabilities.d.ts +101 -0
  33. package/dist/src/generators/shared/capabilities.js +279 -0
  34. package/dist/src/generators/shared/capabilities.js.map +1 -0
  35. package/dist/src/generators/shared/provenance.d.ts +2 -0
  36. package/dist/src/generators/shared/provenance.js +85 -0
  37. package/dist/src/generators/shared/provenance.js.map +1 -0
  38. package/dist/src/generators/shared/scaffold-helpers.d.ts +72 -0
  39. package/dist/src/generators/shared/scaffold-helpers.js +309 -0
  40. package/dist/src/generators/shared/scaffold-helpers.js.map +1 -0
  41. package/dist/src/generators/system-test-runner/generator.d.ts +23 -0
  42. package/dist/src/generators/system-test-runner/generator.js +173 -0
  43. package/dist/src/generators/system-test-runner/generator.js.map +1 -0
  44. package/dist/src/generators/workspace-dev-cli/generator.d.ts +7 -0
  45. package/dist/src/generators/workspace-dev-cli/generator.js +138 -0
  46. package/dist/src/generators/workspace-dev-cli/generator.js.map +1 -0
  47. package/generators.json +57 -0
  48. package/lib/repo-map/grammars/tree-sitter-c.wasm +0 -0
  49. package/lib/repo-map/grammars/tree-sitter-cpp.wasm +0 -0
  50. package/lib/repo-map/grammars/tree-sitter-csharp.wasm +0 -0
  51. package/lib/repo-map/grammars/tree-sitter-dart.wasm +0 -0
  52. package/lib/repo-map/grammars/tree-sitter-go.wasm +0 -0
  53. package/lib/repo-map/grammars/tree-sitter-java.wasm +0 -0
  54. package/lib/repo-map/grammars/tree-sitter-javascript.wasm +0 -0
  55. package/lib/repo-map/grammars/tree-sitter-kotlin.wasm +0 -0
  56. package/lib/repo-map/grammars/tree-sitter-lua.wasm +0 -0
  57. package/lib/repo-map/grammars/tree-sitter-php.wasm +0 -0
  58. package/lib/repo-map/grammars/tree-sitter-python.wasm +0 -0
  59. package/lib/repo-map/grammars/tree-sitter-ruby.wasm +0 -0
  60. package/lib/repo-map/grammars/tree-sitter-rust.wasm +0 -0
  61. package/lib/repo-map/grammars/tree-sitter-scala.wasm +0 -0
  62. package/lib/repo-map/grammars/tree-sitter-swift.wasm +0 -0
  63. package/lib/repo-map/grammars/tree-sitter-tsx.wasm +0 -0
  64. package/lib/repo-map/grammars/tree-sitter-typescript.wasm +0 -0
  65. package/lib/repo-map/index.js +386 -0
  66. package/lib/repo-map/languages.js +514 -0
  67. package/lib/repo-map/pagerank.js +59 -0
  68. package/migrations/README.md +60 -0
  69. package/migrations/_template/cli-migration.js +27 -0
  70. package/migrations/gw-bet-prose-redesign.js +105 -0
  71. package/migrations/gw-drop-test-manifest.js +37 -0
  72. package/migrations/gw-register-serena-mcp.js +42 -0
  73. package/migrations/gw-relocate-hidden-skills.js +40 -0
  74. package/migrations/gw-seed-config-toml.js +24 -0
  75. package/migrations/index.json +40 -0
  76. package/package.json +70 -6
  77. package/src/AGENTS.md +36 -0
  78. package/src/config/config.toml +30 -0
  79. package/src/config/groundwork-state.json +5 -0
  80. package/src/docs/llms.txt +72 -0
  81. package/src/docs/principles/ai-native/agent-native-systems.md +90 -0
  82. package/src/docs/principles/ai-native/agentic-systems.md +78 -0
  83. package/src/docs/principles/ai-native/ai-engineering.md +100 -0
  84. package/src/docs/principles/ai-native/ai-native-product.md +76 -0
  85. package/src/docs/principles/delivery/cost-engineering.md +89 -0
  86. package/src/docs/principles/delivery/day-2-operational-baseline.md +57 -0
  87. package/src/docs/principles/delivery/devex.md +88 -0
  88. package/src/docs/principles/delivery/platform.md +101 -0
  89. package/src/docs/principles/delivery/progressive-delivery.md +92 -0
  90. package/src/docs/principles/design/ai-native-design.md +73 -0
  91. package/src/docs/principles/design/design-foundations.md +80 -0
  92. package/src/docs/principles/design/design-systems-and-tokens.md +72 -0
  93. package/src/docs/principles/design/interaction-and-motion.md +69 -0
  94. package/src/docs/principles/design/layout-and-space.md +72 -0
  95. package/src/docs/principles/design/usability-and-ux.md +79 -0
  96. package/src/docs/principles/design/visual-design.md +84 -0
  97. package/src/docs/principles/foundations/code-craft.md +86 -0
  98. package/src/docs/principles/foundations/continuous-discovery.md +75 -0
  99. package/src/docs/principles/foundations/documentation.md +102 -0
  100. package/src/docs/principles/foundations/prioritization-and-appetite.md +78 -0
  101. package/src/docs/principles/foundations/product-engineering.md +90 -0
  102. package/src/docs/principles/foundations/product-risks.md +89 -0
  103. package/src/docs/principles/foundations/requirements-and-specs.md +80 -0
  104. package/src/docs/principles/foundations/success-metrics.md +66 -0
  105. package/src/docs/principles/foundations/testing.md +108 -0
  106. package/src/docs/principles/index.md +24 -0
  107. package/src/docs/principles/quality/accessibility.md +88 -0
  108. package/src/docs/principles/quality/observability.md +84 -0
  109. package/src/docs/principles/quality/performance.md +84 -0
  110. package/src/docs/principles/quality/privacy.md +92 -0
  111. package/src/docs/principles/quality/reliability.md +89 -0
  112. package/src/docs/principles/quality/security.md +78 -0
  113. package/src/docs/principles/stack/postgres.md +100 -0
  114. package/src/docs/principles/system-design/api-design.md +86 -0
  115. package/src/docs/principles/system-design/architecture-decisions.md +81 -0
  116. package/src/docs/principles/system-design/code-structure.md +104 -0
  117. package/src/docs/principles/system-design/data-engineering.md +87 -0
  118. package/src/docs/principles/system-design/durable-execution.md +89 -0
  119. package/src/docs/principles/system-design/evolutionary-architecture.md +81 -0
  120. package/src/docs/principles/system-design/identity-and-access.md +76 -0
  121. package/src/docs/principles/system-design/integration-patterns.md +84 -0
  122. package/src/docs/principles/system-design/real-time.md +83 -0
  123. package/src/docs/principles/system-design/surface-architecture.md +74 -0
  124. package/src/docs/ways-of-working/documentation.md +69 -0
  125. package/src/docs/ways-of-working/how-we-work.md +76 -0
  126. package/src/docs/ways-of-working/units-of-work.md +40 -0
  127. package/src/engineer-skills/groundwork-electron-engineer/SKILL.md +123 -0
  128. package/src/engineer-skills/groundwork-electron-engineer/references/documentation.md +126 -0
  129. package/src/engineer-skills/groundwork-electron-engineer/references/ipc-contracts.md +138 -0
  130. package/src/engineer-skills/groundwork-electron-engineer/references/observability.md +37 -0
  131. package/src/engineer-skills/groundwork-electron-engineer/references/packaging-and-updates.md +82 -0
  132. package/src/engineer-skills/groundwork-electron-engineer/references/performance-and-reliability.md +80 -0
  133. package/src/engineer-skills/groundwork-electron-engineer/references/process-model.md +94 -0
  134. package/src/engineer-skills/groundwork-electron-engineer/references/security.md +107 -0
  135. package/src/engineer-skills/groundwork-electron-engineer/references/testing-and-smoke.md +129 -0
  136. package/src/engineer-skills/groundwork-electron-engineer/references/theming-and-tokens.md +74 -0
  137. package/src/engineer-skills/groundwork-electron-engineer/sync-anchor.md +22 -0
  138. package/src/engineer-skills/groundwork-flutter-engineer/SKILL.md +114 -0
  139. package/src/engineer-skills/groundwork-flutter-engineer/references/accessibility.md +92 -0
  140. package/src/engineer-skills/groundwork-flutter-engineer/references/architecture.md +189 -0
  141. package/src/engineer-skills/groundwork-flutter-engineer/references/data-and-contracts.md +136 -0
  142. package/src/engineer-skills/groundwork-flutter-engineer/references/documentation.md +122 -0
  143. package/src/engineer-skills/groundwork-flutter-engineer/references/navigation.md +122 -0
  144. package/src/engineer-skills/groundwork-flutter-engineer/references/observability.md +37 -0
  145. package/src/engineer-skills/groundwork-flutter-engineer/references/performance-and-reliability.md +100 -0
  146. package/src/engineer-skills/groundwork-flutter-engineer/references/platform-channels.md +93 -0
  147. package/src/engineer-skills/groundwork-flutter-engineer/references/releases-and-distribution.md +84 -0
  148. package/src/engineer-skills/groundwork-flutter-engineer/references/security.md +96 -0
  149. package/src/engineer-skills/groundwork-flutter-engineer/references/state-management.md +166 -0
  150. package/src/engineer-skills/groundwork-flutter-engineer/references/testing.md +160 -0
  151. package/src/engineer-skills/groundwork-flutter-engineer/references/theming-and-design-tokens.md +109 -0
  152. package/src/engineer-skills/groundwork-flutter-engineer/references/widgets-and-composition.md +123 -0
  153. package/src/engineer-skills/groundwork-flutter-engineer/sync-anchor.md +24 -0
  154. package/src/engineer-skills/groundwork-go-engineer/SKILL.md +174 -0
  155. package/src/engineer-skills/groundwork-go-engineer/references/api-design.md +82 -0
  156. package/src/engineer-skills/groundwork-go-engineer/references/architecture.md +42 -0
  157. package/src/engineer-skills/groundwork-go-engineer/references/capability-ports.md +50 -0
  158. package/src/engineer-skills/groundwork-go-engineer/references/code-craft-security.md +34 -0
  159. package/src/engineer-skills/groundwork-go-engineer/references/concurrency.md +108 -0
  160. package/src/engineer-skills/groundwork-go-engineer/references/documentation.md +130 -0
  161. package/src/engineer-skills/groundwork-go-engineer/references/go-services.md +77 -0
  162. package/src/engineer-skills/groundwork-go-engineer/references/http-handlers.md +172 -0
  163. package/src/engineer-skills/groundwork-go-engineer/references/implementation-patterns.md +156 -0
  164. package/src/engineer-skills/groundwork-go-engineer/references/integration-realtime-data.md +57 -0
  165. package/src/engineer-skills/groundwork-go-engineer/references/observability.md +49 -0
  166. package/src/engineer-skills/groundwork-go-engineer/references/postgres.md +41 -0
  167. package/src/engineer-skills/groundwork-go-engineer/references/reliability-performance.md +105 -0
  168. package/src/engineer-skills/groundwork-go-engineer/references/testing.md +201 -0
  169. package/src/engineer-skills/groundwork-go-engineer/sync-anchor.md +20 -0
  170. package/src/engineer-skills/groundwork-nextjs-engineer/SKILL.md +112 -0
  171. package/src/engineer-skills/groundwork-nextjs-engineer/references/accessibility.md +111 -0
  172. package/src/engineer-skills/groundwork-nextjs-engineer/references/architecture.md +323 -0
  173. package/src/engineer-skills/groundwork-nextjs-engineer/references/data-fetching.md +458 -0
  174. package/src/engineer-skills/groundwork-nextjs-engineer/references/documentation.md +324 -0
  175. package/src/engineer-skills/groundwork-nextjs-engineer/references/error-boundaries.md +383 -0
  176. package/src/engineer-skills/groundwork-nextjs-engineer/references/mutations-and-forms.md +396 -0
  177. package/src/engineer-skills/groundwork-nextjs-engineer/references/observability.md +48 -0
  178. package/src/engineer-skills/groundwork-nextjs-engineer/references/performance-and-deployment.md +947 -0
  179. package/src/engineer-skills/groundwork-nextjs-engineer/references/routing-and-navigation.md +405 -0
  180. package/src/engineer-skills/groundwork-nextjs-engineer/references/security.md +131 -0
  181. package/src/engineer-skills/groundwork-nextjs-engineer/references/server-components.md +394 -0
  182. package/src/engineer-skills/groundwork-nextjs-engineer/references/tailwind-and-styling.md +134 -0
  183. package/src/engineer-skills/groundwork-nextjs-engineer/references/testing.md +491 -0
  184. package/src/engineer-skills/groundwork-nextjs-engineer/references/type-system.md +368 -0
  185. package/src/engineer-skills/groundwork-nextjs-engineer/references/ux-principles.md +230 -0
  186. package/src/engineer-skills/groundwork-nextjs-engineer/references/visual-language.md +69 -0
  187. package/src/engineer-skills/groundwork-nextjs-engineer/sync-anchor.md +16 -0
  188. package/src/engineer-skills/groundwork-python-engineer/SKILL.md +199 -0
  189. package/src/engineer-skills/groundwork-python-engineer/references/api-standards.md +88 -0
  190. package/src/engineer-skills/groundwork-python-engineer/references/architecture.md +57 -0
  191. package/src/engineer-skills/groundwork-python-engineer/references/async-patterns.md +103 -0
  192. package/src/engineer-skills/groundwork-python-engineer/references/capability-ports.md +44 -0
  193. package/src/engineer-skills/groundwork-python-engineer/references/database.md +88 -0
  194. package/src/engineer-skills/groundwork-python-engineer/references/documentation-mcp.md +167 -0
  195. package/src/engineer-skills/groundwork-python-engineer/references/implementation-patterns.md +166 -0
  196. package/src/engineer-skills/groundwork-python-engineer/references/ml-pipelines.md +119 -0
  197. package/src/engineer-skills/groundwork-python-engineer/references/ml-systems-ai-engineering.md +74 -0
  198. package/src/engineer-skills/groundwork-python-engineer/references/observability.md +57 -0
  199. package/src/engineer-skills/groundwork-python-engineer/references/resilience.md +126 -0
  200. package/src/engineer-skills/groundwork-python-engineer/references/security.md +148 -0
  201. package/src/engineer-skills/groundwork-python-engineer/references/testing.md +216 -0
  202. package/src/engineer-skills/groundwork-python-engineer/sync-anchor.md +20 -0
  203. package/src/generators/add-capability/generator.ts +70 -0
  204. package/src/generators/add-capability/schema.json +30 -0
  205. package/src/generators/capabilities/llm/capability.json +28 -0
  206. package/src/generators/capabilities/llm/providers/anthropic/footprint.json +13 -0
  207. package/src/generators/capabilities/llm/providers/anthropic/stacks/go/internal/llm/llm.go.template +102 -0
  208. package/src/generators/capabilities/llm/providers/anthropic/stacks/python/src/__packageName__/adapters/llm.py.template +61 -0
  209. package/src/generators/capabilities/llm/providers/local/footprint.json +13 -0
  210. package/src/generators/capabilities/llm/providers/local/stacks/go/internal/llm/llm.go.template +102 -0
  211. package/src/generators/capabilities/llm/providers/local/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  212. package/src/generators/capabilities/llm/providers/localai/footprint.json +29 -0
  213. package/src/generators/capabilities/llm/providers/localai/stacks/go/internal/llm/llm.go.template +102 -0
  214. package/src/generators/capabilities/llm/providers/localai/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  215. package/src/generators/capabilities/llm/providers/none/footprint.json +9 -0
  216. package/src/generators/capabilities/llm/providers/none/stacks/go/internal/llm/llm.go.template +35 -0
  217. package/src/generators/capabilities/llm/providers/none/stacks/python/src/__packageName__/adapters/llm.py.template +25 -0
  218. package/src/generators/capabilities/llm/providers/ollama/footprint.json +20 -0
  219. package/src/generators/capabilities/llm/providers/ollama/stacks/go/internal/llm/llm.go.template +102 -0
  220. package/src/generators/capabilities/llm/providers/ollama/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  221. package/src/generators/capabilities/llm/providers/openai/footprint.json +13 -0
  222. package/src/generators/capabilities/llm/providers/openai/stacks/go/internal/llm/llm.go.template +98 -0
  223. package/src/generators/capabilities/llm/providers/openai/stacks/python/src/__packageName__/adapters/llm.py.template +60 -0
  224. package/src/generators/capabilities/llm/stacks/go/internal/core/service/llm.go.template +12 -0
  225. package/src/generators/capabilities/llm/stacks/go/internal/llm/llm_test.go.template +33 -0
  226. package/src/generators/capabilities/llm/stacks/python/src/__packageName__/core/llm.py.template +15 -0
  227. package/src/generators/capabilities/llm/stacks/python/tests/contracts/test_llm.py.template +37 -0
  228. package/src/generators/cli-app/files/README.md.template +76 -0
  229. package/src/generators/cli-app/files/build.mjs.template +15 -0
  230. package/src/generators/cli-app/files/package.json.template +21 -0
  231. package/src/generators/cli-app/files/src/cli.ts.template +67 -0
  232. package/src/generators/cli-app/files/src/commands/hello.ts.template +17 -0
  233. package/src/generators/cli-app/files/src/commands/status.ts.template +23 -0
  234. package/src/generators/cli-app/files/src/core/client.test.ts.template +80 -0
  235. package/src/generators/cli-app/files/src/core/client.ts.template +64 -0
  236. package/src/generators/cli-app/files/src/registry.test.ts.template +35 -0
  237. package/src/generators/cli-app/files/src/registry.ts.template +31 -0
  238. package/src/generators/cli-app/files/tsconfig.json.template +16 -0
  239. package/src/generators/cli-app/files/tsconfig.test.json.template +11 -0
  240. package/src/generators/cli-app/generator.ts +138 -0
  241. package/src/generators/cli-app/schema.json +24 -0
  242. package/src/generators/docs-site/files/.gitignore.ejs +40 -0
  243. package/src/generators/docs-site/files/app/docs/__slug__/page.tsx +101 -0
  244. package/src/generators/docs-site/files/app/docs/layout.tsx +14 -0
  245. package/src/generators/docs-site/files/app/docs.css +43 -0
  246. package/src/generators/docs-site/files/app/layout.tsx +24 -0
  247. package/src/generators/docs-site/files/app/page.tsx +135 -0
  248. package/src/generators/docs-site/files/app/source.ts +8 -0
  249. package/src/generators/docs-site/files/components/mermaid.tsx +67 -0
  250. package/src/generators/docs-site/files/next.config.mjs +10 -0
  251. package/src/generators/docs-site/files/package.json +32 -0
  252. package/src/generators/docs-site/files/pnpm-workspace.yaml +7 -0
  253. package/src/generators/docs-site/files/postcss.config.mjs +6 -0
  254. package/src/generators/docs-site/files/source.config.ts +77 -0
  255. package/src/generators/docs-site/files/tailwind.config.js +10 -0
  256. package/src/generators/docs-site/files/tsconfig.json +27 -0
  257. package/src/generators/docs-site/generator.ts +476 -0
  258. package/src/generators/docs-site/schema.json +17 -0
  259. package/src/generators/electron-app/docs/principles/stack/electron/index.md +49 -0
  260. package/src/generators/electron-app/docs/principles/stack/electron/ipc-contracts.md +71 -0
  261. package/src/generators/electron-app/docs/principles/stack/electron/packaging-and-updates.md +59 -0
  262. package/src/generators/electron-app/docs/principles/stack/electron/process-model.md +53 -0
  263. package/src/generators/electron-app/docs/principles/stack/electron/security.md +70 -0
  264. package/src/generators/electron-app/docs/principles/stack/typescript/frontend.md +65 -0
  265. package/src/generators/electron-app/files/.gitignore.template +20 -0
  266. package/src/generators/electron-app/files/README.md.template +125 -0
  267. package/src/generators/electron-app/files/electron.vite.config.ts +31 -0
  268. package/src/generators/electron-app/files/eslint.config.mjs +92 -0
  269. package/src/generators/electron-app/files/forge.config.ts.template +44 -0
  270. package/src/generators/electron-app/files/package.json.template +54 -0
  271. package/src/generators/electron-app/files/playwright.config.ts +18 -0
  272. package/src/generators/electron-app/files/project.json.template +65 -0
  273. package/src/generators/electron-app/files/src/main/core-client.test.ts +81 -0
  274. package/src/generators/electron-app/files/src/main/core-client.ts +55 -0
  275. package/src/generators/electron-app/files/src/main/index.ts +157 -0
  276. package/src/generators/electron-app/files/src/main/ipc.ts +52 -0
  277. package/src/generators/electron-app/files/src/main/policy.test.ts +71 -0
  278. package/src/generators/electron-app/files/src/main/policy.ts +73 -0
  279. package/src/generators/electron-app/files/src/preload/index.ts +23 -0
  280. package/src/generators/electron-app/files/src/renderer/index.html.template +20 -0
  281. package/src/generators/electron-app/files/src/renderer/src/App.test.tsx +61 -0
  282. package/src/generators/electron-app/files/src/renderer/src/App.tsx.template +43 -0
  283. package/src/generators/electron-app/files/src/renderer/src/assets/main.css +40 -0
  284. package/src/generators/electron-app/files/src/renderer/src/env.d.ts +14 -0
  285. package/src/generators/electron-app/files/src/renderer/src/main.tsx +25 -0
  286. package/src/generators/electron-app/files/src/shared/ipc.ts +54 -0
  287. package/src/generators/electron-app/files/tests/smoke/app.spec.ts.template +133 -0
  288. package/src/generators/electron-app/files/tool/electron_exec.sh.template +83 -0
  289. package/src/generators/electron-app/files/tsconfig.json +7 -0
  290. package/src/generators/electron-app/files/tsconfig.node.json +27 -0
  291. package/src/generators/electron-app/files/tsconfig.web.json +22 -0
  292. package/src/generators/electron-app/files/vitest.config.ts +32 -0
  293. package/src/generators/electron-app/files/vitest.setup.ts +1 -0
  294. package/src/generators/electron-app/generator.ts +288 -0
  295. package/src/generators/electron-app/schema.json +23 -0
  296. package/src/generators/flutter-app/docs/principles/stack/flutter/architecture.md +78 -0
  297. package/src/generators/flutter-app/docs/principles/stack/flutter/index.md +38 -0
  298. package/src/generators/flutter-app/docs/principles/stack/flutter/platform-channels.md +51 -0
  299. package/src/generators/flutter-app/docs/principles/stack/flutter/releases-and-distribution.md +59 -0
  300. package/src/generators/flutter-app/docs/principles/stack/flutter/state-management.md +85 -0
  301. package/src/generators/flutter-app/docs/principles/stack/flutter/testing.md +86 -0
  302. package/src/generators/flutter-app/docs/principles/stack/flutter/widgets-and-composition.md +69 -0
  303. package/src/generators/flutter-app/files/.gitignore.template +30 -0
  304. package/src/generators/flutter-app/files/README.md.template +100 -0
  305. package/src/generators/flutter-app/files/analysis_options.yaml.template +18 -0
  306. package/src/generators/flutter-app/files/integration_test/app_test.dart.template +64 -0
  307. package/src/generators/flutter-app/files/lib/app.dart.template +24 -0
  308. package/src/generators/flutter-app/files/lib/config/app_config.dart +15 -0
  309. package/src/generators/flutter-app/files/lib/data/repositories/status_repository.dart +36 -0
  310. package/src/generators/flutter-app/files/lib/data/services/api_client.dart +71 -0
  311. package/src/generators/flutter-app/files/lib/domain/models/health_status.dart +23 -0
  312. package/src/generators/flutter-app/files/lib/main.dart +11 -0
  313. package/src/generators/flutter-app/files/lib/router.dart +23 -0
  314. package/src/generators/flutter-app/files/lib/ui/core/theme/app_theme.dart +110 -0
  315. package/src/generators/flutter-app/files/lib/ui/home/home_view.dart +89 -0
  316. package/src/generators/flutter-app/files/lib/ui/home/home_view_model.dart.template +38 -0
  317. package/src/generators/flutter-app/files/project.json.template +51 -0
  318. package/src/generators/flutter-app/files/pubspec.yaml.template +47 -0
  319. package/src/generators/flutter-app/files/test/api_client_test.dart.template +63 -0
  320. package/src/generators/flutter-app/files/test/fakes/fake_status_repository.dart.template +19 -0
  321. package/src/generators/flutter-app/files/test/home_view_test.dart.template +58 -0
  322. package/src/generators/flutter-app/files/tool/flutter_exec.sh.template +60 -0
  323. package/src/generators/flutter-app/generator.ts +362 -0
  324. package/src/generators/flutter-app/schema.json +23 -0
  325. package/src/generators/go-microservice/docs/principles/stack/go/concurrency.md +123 -0
  326. package/src/generators/go-microservice/docs/principles/stack/go/index.md +70 -0
  327. package/src/generators/go-microservice/docs/principles/stack/go/testing.md +168 -0
  328. package/src/generators/go-microservice/files/.air.toml.template +38 -0
  329. package/src/generators/go-microservice/files/.env.template +4 -0
  330. package/src/generators/go-microservice/files/.golangci.yml.template +82 -0
  331. package/src/generators/go-microservice/files/Dockerfile.dev.template +12 -0
  332. package/src/generators/go-microservice/files/asyncapi-pubsub.yaml.template +33 -0
  333. package/src/generators/go-microservice/files/asyncapi-ws.yaml.template +34 -0
  334. package/src/generators/go-microservice/files/cmd/api/main.go.template +149 -0
  335. package/src/generators/go-microservice/files/cmd/api/main_test.go.template +99 -0
  336. package/src/generators/go-microservice/files/cmd/worker/cleanup/main.go.template +39 -0
  337. package/src/generators/go-microservice/files/db/schema.sql.template +24 -0
  338. package/src/generators/go-microservice/files/go.mod.template +39 -0
  339. package/src/generators/go-microservice/files/internal/config/config.go.template +52 -0
  340. package/src/generators/go-microservice/files/internal/config/otel.go.template +93 -0
  341. package/src/generators/go-microservice/files/internal/core/domain/errors.go.template +16 -0
  342. package/src/generators/go-microservice/files/internal/core/domain/model.go.template +28 -0
  343. package/src/generators/go-microservice/files/internal/core/domain/user.go.template +13 -0
  344. package/src/generators/go-microservice/files/internal/core/pagination.go.template +16 -0
  345. package/src/generators/go-microservice/files/internal/core/service/app_service.go.template +79 -0
  346. package/src/generators/go-microservice/files/internal/core/service/event_hub.go.template +9 -0
  347. package/src/generators/go-microservice/files/internal/core/service/message_queue.go.template +10 -0
  348. package/src/generators/go-microservice/files/internal/core/service/outbox_repository.go.template +31 -0
  349. package/src/generators/go-microservice/files/internal/core/service/repository.go.template +23 -0
  350. package/src/generators/go-microservice/files/internal/core/service/user_repository.go.template +15 -0
  351. package/src/generators/go-microservice/files/internal/core/service/user_service.go.template +43 -0
  352. package/src/generators/go-microservice/files/internal/entrypoints/api/app_handler.go.template +108 -0
  353. package/src/generators/go-microservice/files/internal/entrypoints/api/auth_middleware_test.go.template +52 -0
  354. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook.go.template +202 -0
  355. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook_test.go.template +82 -0
  356. package/src/generators/go-microservice/files/internal/entrypoints/api/health_handler.go.template +80 -0
  357. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware.go.template +87 -0
  358. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware_test.go.template +76 -0
  359. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/repository.go.template +37 -0
  360. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_auth.go.template +40 -0
  361. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_loadshed.go.template +38 -0
  362. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_logging.go.template +40 -0
  363. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_ratelimit.go.template +48 -0
  364. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_test.go.template +81 -0
  365. package/src/generators/go-microservice/files/internal/entrypoints/api/router.go.template +105 -0
  366. package/src/generators/go-microservice/files/internal/entrypoints/api/types.go.template +70 -0
  367. package/src/generators/go-microservice/files/internal/entrypoints/api/websocket_handler.go.template +39 -0
  368. package/src/generators/go-microservice/files/internal/httpclient/http_client.go.template +87 -0
  369. package/src/generators/go-microservice/files/internal/kafka/kafka.go.template +34 -0
  370. package/src/generators/go-microservice/files/internal/postgres/postgres.go.template +195 -0
  371. package/src/generators/go-microservice/files/internal/postgres/postgres_test.go.template +156 -0
  372. package/src/generators/go-microservice/files/internal/postgres/user_repository.go.template +56 -0
  373. package/src/generators/go-microservice/files/internal/pubsub/gcp_pubsub.go.template +35 -0
  374. package/src/generators/go-microservice/files/internal/websocket/client.go.template +151 -0
  375. package/src/generators/go-microservice/files/internal/websocket/hub.go.template +261 -0
  376. package/src/generators/go-microservice/files/scripts/apply-schema.sh.template +21 -0
  377. package/src/generators/go-microservice/files/tools/tools.go.template +10 -0
  378. package/src/generators/go-microservice/generator.ts +240 -0
  379. package/src/generators/go-microservice/schema.json +63 -0
  380. package/src/generators/nextjs-app/docs/principles/stack/typescript/frontend.md +65 -0
  381. package/src/generators/nextjs-app/files/.dockerignore.template +7 -0
  382. package/src/generators/nextjs-app/files/.env.example.template +24 -0
  383. package/src/generators/nextjs-app/files/.gitignore.template +5 -0
  384. package/src/generators/nextjs-app/files/Dockerfile +53 -0
  385. package/src/generators/nextjs-app/files/app/(auth)/sign-in/__sign-in__/page.tsx.template +9 -0
  386. package/src/generators/nextjs-app/files/app/(auth)/sign-up/__sign-up__/page.tsx.template +9 -0
  387. package/src/generators/nextjs-app/files/app/api/config/route.ts.template +39 -0
  388. package/src/generators/nextjs-app/files/app/api/healthz/route.test.ts +15 -0
  389. package/src/generators/nextjs-app/files/app/api/healthz/route.ts +5 -0
  390. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.test.ts.template +55 -0
  391. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.ts.template +126 -0
  392. package/src/generators/nextjs-app/files/app/error.tsx +39 -0
  393. package/src/generators/nextjs-app/files/app/global-error.tsx +68 -0
  394. package/src/generators/nextjs-app/files/app/globals.css +105 -0
  395. package/src/generators/nextjs-app/files/app/layout.tsx +59 -0
  396. package/src/generators/nextjs-app/files/app/loading.tsx +13 -0
  397. package/src/generators/nextjs-app/files/app/not-found.tsx +30 -0
  398. package/src/generators/nextjs-app/files/app/page.tsx +20 -0
  399. package/src/generators/nextjs-app/files/components/providers/default.tsx +19 -0
  400. package/src/generators/nextjs-app/files/components/providers/production.tsx +32 -0
  401. package/src/generators/nextjs-app/files/components/providers/telemetry.tsx +76 -0
  402. package/src/generators/nextjs-app/files/components/render-smoke.test.tsx +29 -0
  403. package/src/generators/nextjs-app/files/components/theme-provider.tsx +11 -0
  404. package/src/generators/nextjs-app/files/components.json +21 -0
  405. package/src/generators/nextjs-app/files/eslint.config.mjs +120 -0
  406. package/src/generators/nextjs-app/files/hooks/use-toast.ts +7 -0
  407. package/src/generators/nextjs-app/files/instrumentation.ts +90 -0
  408. package/src/generators/nextjs-app/files/lib/api/fetcher.ts.template +130 -0
  409. package/src/generators/nextjs-app/files/lib/config.ts +21 -0
  410. package/src/generators/nextjs-app/files/lib/logger.ts +29 -0
  411. package/src/generators/nextjs-app/files/lib/schemas/index.ts +19 -0
  412. package/src/generators/nextjs-app/files/lib/utils.ts +6 -0
  413. package/src/generators/nextjs-app/files/next.config.mjs +9 -0
  414. package/src/generators/nextjs-app/files/package.json +70 -0
  415. package/src/generators/nextjs-app/files/postcss.config.mjs +8 -0
  416. package/src/generators/nextjs-app/files/proxy.test.ts.template +30 -0
  417. package/src/generators/nextjs-app/files/proxy.ts +31 -0
  418. package/src/generators/nextjs-app/files/public/.gitkeep +1 -0
  419. package/src/generators/nextjs-app/files/tsconfig.json +42 -0
  420. package/src/generators/nextjs-app/files/vitest.config.mts +15 -0
  421. package/src/generators/nextjs-app/files/vitest.setup.ts +7 -0
  422. package/src/generators/nextjs-app/generator.ts +307 -0
  423. package/src/generators/nextjs-app/schema.json +44 -0
  424. package/src/generators/python-microservice/docs/principles/stack/python/async.md +168 -0
  425. package/src/generators/python-microservice/docs/principles/stack/python/documentation.md +240 -0
  426. package/src/generators/python-microservice/docs/principles/stack/python/mcp.md +147 -0
  427. package/src/generators/python-microservice/docs/principles/stack/python/resilience.md +193 -0
  428. package/src/generators/python-microservice/docs/principles/stack/python/testing.md +322 -0
  429. package/src/generators/python-microservice/files/.env.example.template +30 -0
  430. package/src/generators/python-microservice/files/Dockerfile.template +36 -0
  431. package/src/generators/python-microservice/files/db/schema.sql.template +19 -0
  432. package/src/generators/python-microservice/files/pyproject.toml.template +76 -0
  433. package/src/generators/python-microservice/files/scripts/apply-schema.sh.template +25 -0
  434. package/src/generators/python-microservice/files/src/__packageName__/adapters/comfyui.py.template +87 -0
  435. package/src/generators/python-microservice/files/src/__packageName__/adapters/config.py.template +48 -0
  436. package/src/generators/python-microservice/files/src/__packageName__/adapters/database.py.template +21 -0
  437. package/src/generators/python-microservice/files/src/__packageName__/adapters/message_queue.py.template +29 -0
  438. package/src/generators/python-microservice/files/src/__packageName__/adapters/repository.py.template +130 -0
  439. package/src/generators/python-microservice/files/src/__packageName__/adapters/telemetry.py.template +68 -0
  440. package/src/generators/python-microservice/files/src/__packageName__/adapters/websocket_hub.py.template +36 -0
  441. package/src/generators/python-microservice/files/src/__packageName__/core/domain/entities.py.template +22 -0
  442. package/src/generators/python-microservice/files/src/__packageName__/core/domain/exceptions.py.template +43 -0
  443. package/src/generators/python-microservice/files/src/__packageName__/core/ports.py.template +42 -0
  444. package/src/generators/python-microservice/files/src/__packageName__/core/service/example_service.py.template +68 -0
  445. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/dependencies.py.template +50 -0
  446. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/middleware.py.template +131 -0
  447. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/router.py.template +37 -0
  448. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/websocket_handler.py.template +20 -0
  449. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/cleanup.py.template +35 -0
  450. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/worker.py.template +28 -0
  451. package/src/generators/python-microservice/files/src/__packageName__/main.py.template +108 -0
  452. package/src/generators/python-microservice/files/tests/test_main.py.template +74 -0
  453. package/src/generators/python-microservice/files/tests/test_middleware.py.template +109 -0
  454. package/src/generators/python-microservice/files/tests/test_worker.py.template +16 -0
  455. package/src/generators/python-microservice/generator.ts +286 -0
  456. package/src/generators/python-microservice/schema.json +86 -0
  457. package/src/generators/shared/brand-tokens.ts +301 -0
  458. package/src/generators/shared/capabilities.ts +349 -0
  459. package/src/generators/shared/provenance.ts +61 -0
  460. package/src/generators/shared/scaffold-helpers.ts +309 -0
  461. package/src/generators/system-test-runner/NATIVE-CHECK-CONTRACT.md +20 -0
  462. package/src/generators/system-test-runner/files/tests/bets/.gitkeep +0 -0
  463. package/src/generators/system-test-runner/files/tests/bets/_archive/.gitkeep +0 -0
  464. package/src/generators/system-test-runner/files/tests/conftest.py.template +503 -0
  465. package/src/generators/system-test-runner/files/tests/pyproject.toml.template +20 -0
  466. package/src/generators/system-test-runner/files/tests/system/pages/__init__.py.template +9 -0
  467. package/src/generators/system-test-runner/files/tests/system/pages/base_page.py.template +36 -0
  468. package/src/generators/system-test-runner/files/tests/system/test_a11y_smoke.py.template +132 -0
  469. package/src/generators/system-test-runner/files/tests/system/test_contract_conformance.py.template +140 -0
  470. package/src/generators/system-test-runner/files/tests/system/test_layout_geometry.py.template +109 -0
  471. package/src/generators/system-test-runner/files/tests/system/test_render_smoke.py.template +257 -0
  472. package/src/generators/system-test-runner/files/tests/system/test_system.py.template +158 -0
  473. package/src/generators/system-test-runner/files/tests/system/test_token_conformance.py.template +206 -0
  474. package/src/generators/system-test-runner/files/tests/system/test_visual_regression.py.template +104 -0
  475. package/src/generators/system-test-runner/generator.ts +196 -0
  476. package/src/generators/system-test-runner/schema.json +24 -0
  477. package/src/generators/workspace-dev-cli/cli-src/build.mjs +42 -0
  478. package/src/generators/workspace-dev-cli/cli-src/dist/dev-bundle.js +2168 -0
  479. package/src/generators/workspace-dev-cli/cli-src/src/commands/bet.ts +442 -0
  480. package/src/generators/workspace-dev-cli/cli-src/src/commands/completion.ts +87 -0
  481. package/src/generators/workspace-dev-cli/cli-src/src/commands/doctor.ts +139 -0
  482. package/src/generators/workspace-dev-cli/cli-src/src/commands/lifecycle.ts +548 -0
  483. package/src/generators/workspace-dev-cli/cli-src/src/commands/quality.ts +127 -0
  484. package/src/generators/workspace-dev-cli/cli-src/src/commands/surface.ts +214 -0
  485. package/src/generators/workspace-dev-cli/cli-src/src/index.ts +127 -0
  486. package/src/generators/workspace-dev-cli/cli-src/src/registry.ts +194 -0
  487. package/src/generators/workspace-dev-cli/cli-src/src/theme/color.ts +130 -0
  488. package/src/generators/workspace-dev-cli/cli-src/src/theme/render.ts +158 -0
  489. package/src/generators/workspace-dev-cli/cli-src/src/theme/tokens.ts +122 -0
  490. package/src/generators/workspace-dev-cli/cli-src/src/util/context.ts +43 -0
  491. package/src/generators/workspace-dev-cli/cli-src/src/util/extensions.ts +99 -0
  492. package/src/generators/workspace-dev-cli/cli-src/src/util/paths.ts +46 -0
  493. package/src/generators/workspace-dev-cli/cli-src/src/util/proc.ts +106 -0
  494. package/src/generators/workspace-dev-cli/cli-src/src/util/prompt.ts +108 -0
  495. package/src/generators/workspace-dev-cli/cli-src/src/util/runners.ts +70 -0
  496. package/src/generators/workspace-dev-cli/cli-src/src/util/services.ts +221 -0
  497. package/src/generators/workspace-dev-cli/cli-src/src/util/version.ts +21 -0
  498. package/src/generators/workspace-dev-cli/cli-src/tsconfig.json +16 -0
  499. package/src/generators/workspace-dev-cli/files/.agents/skills/workspace-cli/SKILL.md.template +74 -0
  500. package/src/generators/workspace-dev-cli/files/dev.template +16 -0
  501. package/src/generators/workspace-dev-cli/files/docker-compose.yml.template +20 -0
  502. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/milestone-test.pytmpl.template +46 -0
  503. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/slice-test.pytmpl.template +38 -0
  504. package/src/generators/workspace-dev-cli/generator.ts +136 -0
  505. package/src/generators/workspace-dev-cli/schema.json +22 -0
  506. package/src/hidden-skills/code-intelligence.md +135 -0
  507. package/src/hidden-skills/groundwork-architect/SKILL.md +114 -0
  508. package/src/hidden-skills/groundwork-architect/references/agentic-systems.md +44 -0
  509. package/src/hidden-skills/groundwork-architect/references/ai-native-architecture.md +37 -0
  510. package/src/hidden-skills/groundwork-architect/references/api-and-contracts.md +45 -0
  511. package/src/hidden-skills/groundwork-architect/references/core-and-boundaries.md +45 -0
  512. package/src/hidden-skills/groundwork-architect/references/data-architecture.md +33 -0
  513. package/src/hidden-skills/groundwork-architect/references/decision-records.md +34 -0
  514. package/src/hidden-skills/groundwork-architect/references/durable-execution.md +45 -0
  515. package/src/hidden-skills/groundwork-architect/references/evolutionary-architecture.md +37 -0
  516. package/src/hidden-skills/groundwork-architect/references/identity-and-access.md +41 -0
  517. package/src/hidden-skills/groundwork-architect/references/integration-patterns.md +39 -0
  518. package/src/hidden-skills/groundwork-architect/references/observability.md +36 -0
  519. package/src/hidden-skills/groundwork-architect/references/performance-and-scale.md +41 -0
  520. package/src/hidden-skills/groundwork-architect/references/platform-and-delivery.md +47 -0
  521. package/src/hidden-skills/groundwork-architect/references/realtime-and-async.md +28 -0
  522. package/src/hidden-skills/groundwork-architect/references/reliability.md +31 -0
  523. package/src/hidden-skills/groundwork-architect/references/security-and-trust.md +47 -0
  524. package/src/hidden-skills/groundwork-architect/references/surface-architecture.md +40 -0
  525. package/src/hidden-skills/groundwork-architect/sync-anchor.md +34 -0
  526. package/src/hidden-skills/groundwork-architecture/architecture-template.md +50 -0
  527. package/src/hidden-skills/groundwork-architecture/instructions.md +139 -0
  528. package/src/hidden-skills/groundwork-architecture/phases/01-context-ingestion.md +18 -0
  529. package/src/hidden-skills/groundwork-architecture/phases/02-technical-constraints.md +27 -0
  530. package/src/hidden-skills/groundwork-architecture/phases/03-service-design.md +19 -0
  531. package/src/hidden-skills/groundwork-architecture/phases/04-data-flow-communication.md +23 -0
  532. package/src/hidden-skills/groundwork-architecture/phases/05-component-boundaries-contracts.md +17 -0
  533. package/src/hidden-skills/groundwork-architecture/phases/06-draft-review-present.md +38 -0
  534. package/src/hidden-skills/groundwork-architecture/phases/07-commit.md +33 -0
  535. package/src/hidden-skills/groundwork-architecture/templates/architecture-cache.md +43 -0
  536. package/src/hidden-skills/groundwork-architecture-extract/instructions.md +163 -0
  537. package/src/hidden-skills/groundwork-architecture-extract/templates/architecture-extract-cache.md +21 -0
  538. package/src/hidden-skills/groundwork-bet/briefs/acceptance-auditor.md +68 -0
  539. package/src/hidden-skills/groundwork-bet/briefs/blind-reviewer.md +56 -0
  540. package/src/hidden-skills/groundwork-bet/briefs/coverage-auditor.md +95 -0
  541. package/src/hidden-skills/groundwork-bet/briefs/edge-case-tracer.md +64 -0
  542. package/src/hidden-skills/groundwork-bet/briefs/experience-auditor.md +83 -0
  543. package/src/hidden-skills/groundwork-bet/briefs/slice-worker.md +257 -0
  544. package/src/hidden-skills/groundwork-bet/instructions.md +88 -0
  545. package/src/hidden-skills/groundwork-bet/templates/bet-progress-test.md +115 -0
  546. package/src/hidden-skills/groundwork-bet/templates/change-proposal.md +38 -0
  547. package/src/hidden-skills/groundwork-bet/templates/decomposition/meta.json +4 -0
  548. package/src/hidden-skills/groundwork-bet/templates/decomposition/milestone-index.md +31 -0
  549. package/src/hidden-skills/groundwork-bet/templates/decomposition/slice.md +31 -0
  550. package/src/hidden-skills/groundwork-bet/templates/pitch.md +45 -0
  551. package/src/hidden-skills/groundwork-bet/templates/technical-design/01-ui-design.md +51 -0
  552. package/src/hidden-skills/groundwork-bet/templates/technical-design/02-data-flows.md +36 -0
  553. package/src/hidden-skills/groundwork-bet/templates/technical-design/03-api-design.md +90 -0
  554. package/src/hidden-skills/groundwork-bet/templates/technical-design/04-data-design.md +29 -0
  555. package/src/hidden-skills/groundwork-bet/workflows/01-discovery.md +200 -0
  556. package/src/hidden-skills/groundwork-bet/workflows/02-design.md +178 -0
  557. package/src/hidden-skills/groundwork-bet/workflows/03-decomposition.md +242 -0
  558. package/src/hidden-skills/groundwork-bet/workflows/04-delivery.md +226 -0
  559. package/src/hidden-skills/groundwork-bet/workflows/05-validation.md +210 -0
  560. package/src/hidden-skills/groundwork-design-system/instructions.md +125 -0
  561. package/src/hidden-skills/groundwork-design-system/templates/brand-tokens.md +182 -0
  562. package/src/hidden-skills/groundwork-design-system/templates/design-system-cache.md +64 -0
  563. package/src/hidden-skills/groundwork-design-system/tracks/_foundation.md +136 -0
  564. package/src/hidden-skills/groundwork-design-system/tracks/agentic-protocol.md +269 -0
  565. package/src/hidden-skills/groundwork-design-system/tracks/cli.md +355 -0
  566. package/src/hidden-skills/groundwork-design-system/tracks/graphical-ui.md +330 -0
  567. package/src/hidden-skills/groundwork-design-system-extract/instructions.md +124 -0
  568. package/src/hidden-skills/groundwork-design-system-extract/templates/design-system-extract-cache.md +19 -0
  569. package/src/hidden-skills/groundwork-designer/SKILL.md +108 -0
  570. package/src/hidden-skills/groundwork-designer/references/accessibility.md +33 -0
  571. package/src/hidden-skills/groundwork-designer/references/ai-native-design.md +37 -0
  572. package/src/hidden-skills/groundwork-designer/references/design-review.md +29 -0
  573. package/src/hidden-skills/groundwork-designer/references/design-systems-and-tokens.md +33 -0
  574. package/src/hidden-skills/groundwork-designer/references/interaction-and-motion.md +37 -0
  575. package/src/hidden-skills/groundwork-designer/references/layout-and-space.md +33 -0
  576. package/src/hidden-skills/groundwork-designer/references/usability-and-ux.md +33 -0
  577. package/src/hidden-skills/groundwork-designer/references/visual-craft.md +49 -0
  578. package/src/hidden-skills/groundwork-designer/sync-anchor.md +20 -0
  579. package/src/hidden-skills/groundwork-doc-sync/instructions.md +100 -0
  580. package/src/hidden-skills/groundwork-elicit/instructions.md +66 -0
  581. package/src/hidden-skills/groundwork-elicit/methods.md +65 -0
  582. package/src/hidden-skills/groundwork-infra-adopt/instructions.md +168 -0
  583. package/src/hidden-skills/groundwork-infra-adopt/templates/infra-adopt-cache.md +21 -0
  584. package/src/hidden-skills/groundwork-mvp/instructions.md +223 -0
  585. package/src/hidden-skills/groundwork-mvp/templates/mvp-cache.md +9 -0
  586. package/src/hidden-skills/groundwork-patch/instructions.md +40 -0
  587. package/src/hidden-skills/groundwork-persona/instructions.md +65 -0
  588. package/src/hidden-skills/groundwork-product/SKILL.md +102 -0
  589. package/src/hidden-skills/groundwork-product/references/ai-native-product.md +45 -0
  590. package/src/hidden-skills/groundwork-product/references/discovery-and-opportunity.md +38 -0
  591. package/src/hidden-skills/groundwork-product/references/product-risks.md +52 -0
  592. package/src/hidden-skills/groundwork-product/references/requirements-and-specs.md +39 -0
  593. package/src/hidden-skills/groundwork-product/references/scope-and-sequencing.md +35 -0
  594. package/src/hidden-skills/groundwork-product/references/shaping-and-appetite.md +48 -0
  595. package/src/hidden-skills/groundwork-product/references/success-metrics-and-signals.md +37 -0
  596. package/src/hidden-skills/groundwork-product/sync-anchor.md +19 -0
  597. package/src/hidden-skills/groundwork-product-brief/instructions.md +231 -0
  598. package/src/hidden-skills/groundwork-product-brief-extract/instructions.md +139 -0
  599. package/src/hidden-skills/groundwork-product-brief-extract/templates/product-brief-extract-cache.md +17 -0
  600. package/src/hidden-skills/groundwork-review/checklists/architecture.md +93 -0
  601. package/src/hidden-skills/groundwork-review/checklists/bet-pitch.md +94 -0
  602. package/src/hidden-skills/groundwork-review/checklists/decomposition.md +135 -0
  603. package/src/hidden-skills/groundwork-review/checklists/design-system.md +85 -0
  604. package/src/hidden-skills/groundwork-review/checklists/domain-entity.md +66 -0
  605. package/src/hidden-skills/groundwork-review/checklists/implementation-readiness.md +47 -0
  606. package/src/hidden-skills/groundwork-review/checklists/infrastructure.md +68 -0
  607. package/src/hidden-skills/groundwork-review/checklists/maturity.md +71 -0
  608. package/src/hidden-skills/groundwork-review/checklists/product-brief.md +69 -0
  609. package/src/hidden-skills/groundwork-review/checklists/technical-design.md +112 -0
  610. package/src/hidden-skills/groundwork-review/instructions.md +181 -0
  611. package/src/hidden-skills/groundwork-scaffold/instructions.md +254 -0
  612. package/src/hidden-skills/groundwork-scaffold/phases/01-ingestion-service-mapping.md +87 -0
  613. package/src/hidden-skills/groundwork-scaffold/phases/02-scaffolding-execution.md +15 -0
  614. package/src/hidden-skills/groundwork-scaffold/phases/03-service-documentation-api-stubs.md +100 -0
  615. package/src/hidden-skills/groundwork-scaffold/phases/04-infrastructure-verification.md +17 -0
  616. package/src/hidden-skills/groundwork-scaffold/phases/05-draft-review.md +19 -0
  617. package/src/hidden-skills/groundwork-scaffold/phases/06-commit.md +19 -0
  618. package/src/hidden-skills/groundwork-scaffold/templates/scaffold-cache.md +23 -0
  619. package/src/hidden-skills/groundwork-scan/instructions.md +164 -0
  620. package/src/hidden-skills/groundwork-scan/references/digest-schema.md +66 -0
  621. package/src/hidden-skills/groundwork-scan/references/exclusions.md +44 -0
  622. package/src/hidden-skills/groundwork-scan/templates/architecture-findings.md +42 -0
  623. package/src/hidden-skills/groundwork-scan/templates/design-findings.md +23 -0
  624. package/src/hidden-skills/groundwork-scan/templates/overview.md +26 -0
  625. package/src/hidden-skills/groundwork-scan/templates/product-findings.md +23 -0
  626. package/src/hidden-skills/groundwork-scan/templates/scan-state.json +19 -0
  627. package/src/hidden-skills/groundwork-stack-forge/instructions.md +150 -0
  628. package/src/hidden-skills/groundwork-stack-forge/references/authoring-engineer-skills.md +107 -0
  629. package/src/hidden-skills/groundwork-surface-activation/instructions.md +138 -0
  630. package/src/hidden-skills/groundwork-update/briefs/reconcile-worker.md +196 -0
  631. package/src/hidden-skills/groundwork-update/instructions.md +200 -0
  632. package/src/hidden-skills/groundwork-writer/SKILL.md +278 -0
  633. package/src/hidden-skills/maturity-model.md +125 -0
  634. package/src/hidden-skills/operating-contract.md +400 -0
  635. package/src/hidden-skills/repo-map-schema.md +90 -0
  636. package/src/hidden-skills/templates/adr.md +57 -0
  637. package/src/hidden-skills/templates/capability-ports.md +71 -0
  638. package/src/hidden-skills/templates/discovery-notes.md +33 -0
  639. package/src/hidden-skills/templates/domain-entity.md +80 -0
  640. package/src/hidden-skills/templates/gap-ledger.md +21 -0
  641. package/src/hidden-skills/templates/handoff.md +37 -0
  642. package/src/hidden-skills/templates/maturity.md +39 -0
  643. package/src/hidden-skills/templates/surfaces.md +207 -0
  644. package/src/skills/groundwork-check/SKILL.md +56 -0
  645. package/src/skills/groundwork-check/instructions.md +70 -0
  646. package/src/skills/groundwork-orchestrator/SKILL.md +176 -0
  647. package/src/skills/groundwork-orchestrator/workflow-index.md +50 -0
@@ -0,0 +1,503 @@
1
+ """Shared fixtures for the system and bet-progress test suites.
2
+
3
+ This file is the single source of truth for service discovery and state
4
+ management. Both tests/system/ and tests/bets/ import from here.
5
+
6
+ Services and their ports/DBs are DISCOVERED at runtime by parsing the
7
+ workspace docker-compose.yml — there are no hardcoded ports and no
8
+ manifest file. Adding a service to the workspace automatically brings
9
+ it under test.
10
+
11
+ FAIL LOUD, NOT SILENT: when GROUNDWORK_REQUIRE_SERVICES=1 (set by CI and
12
+ by `./dev test integration`), an unreachable service is a FAILURE. Locally
13
+ (flag unset) the same condition skips, so the inner loop stays ergonomic.
14
+ """
15
+
16
+ <% if (flutterSurfaces.length) { -%>
17
+ import json
18
+ <% } -%>
19
+ import os
20
+ <% if (cliSurfaces.length || flutterSurfaces.length || electronSurfaces.length) { -%>
21
+ import shlex
22
+ <% } -%>
23
+ <% if (flutterSurfaces.length) { -%>
24
+ import shutil
25
+ <% } -%>
26
+ <% if (cliSurfaces.length || flutterSurfaces.length || electronSurfaces.length) { -%>
27
+ import subprocess
28
+ <% } -%>
29
+ import uuid
30
+ from pathlib import Path
31
+
32
+ import httpx
33
+ import psycopg
34
+ import pytest
35
+ import yaml
36
+ from tenacity import RetryError, retry, stop_after_delay, wait_exponential
37
+
38
+ # tests/ -> workspace root (conftest.py sits at tests/, one level above system/)
39
+ WORKSPACE_ROOT = Path(__file__).resolve().parent.parent
40
+ COMPOSE_PATH = WORKSPACE_ROOT / "docker-compose.yml"
41
+ SERVICES_DIR = WORKSPACE_ROOT / "services"
42
+
43
+ # Postgres on the dev stack is published to host localhost:5432.
44
+ PG_HOST = "localhost"
45
+ PG_PORT = 5432
46
+ PG_USER = "postgres"
47
+ PG_PASSWORD = "postgres"
48
+
49
+ # Jaeger query API (UI + /api/services + /api/traces) on the dev stack.
50
+ JAEGER_URL = os.environ.get("TRACE_BACKEND_URL", "http://localhost:16686")
51
+
52
+ REQUIRE_SERVICES = os.environ.get("GROUNDWORK_REQUIRE_SERVICES") == "1"
53
+
54
+
55
+ def _infer_type(name: str) -> str:
56
+ """Infer service type from on-disk markers under services/<name>/."""
57
+ svc = SERVICES_DIR / name
58
+ if (svc / "go.mod").exists():
59
+ return "go"
60
+ if (svc / "pyproject.toml").exists():
61
+ return "python"
62
+ if (svc / "package.json").exists():
63
+ return "next"
64
+ return "unknown"
65
+
66
+
67
+ def _health_path_for(svc_type: str) -> str:
68
+ if svc_type == "next":
69
+ return "/api/healthz"
70
+ # Go (huma) and Python (FastAPI) both expose /health.
71
+ return "/health"
72
+
73
+
74
+ def _probe_path_for(svc_type: str) -> str:
75
+ """A real (traced) GET route per service type, used by the span tests.
76
+ /health is excluded from tracing by the otelhttp middleware, so use a
77
+ domain route. Go ships /api/v1/entities; the Python scaffold's example
78
+ router is mounted at /examples."""
79
+ if svc_type == "python":
80
+ return "/examples"
81
+ return "/api/v1/entities"
82
+
83
+
84
+ def _discover_services() -> list[dict]:
85
+ """Parse the workspace docker-compose.yml and return APP services only.
86
+
87
+ Discriminator: an APP service has `build.context` starting with
88
+ `./services/`; infra services use `image:` and are skipped.
89
+ """
90
+ if not COMPOSE_PATH.exists():
91
+ return []
92
+ doc = yaml.safe_load(COMPOSE_PATH.read_text()) or {}
93
+ services = doc.get("services", {}) or {}
94
+ discovered: list[dict] = []
95
+ for name, spec in services.items():
96
+ spec = spec or {}
97
+ build = spec.get("build")
98
+ context = build.get("context") if isinstance(build, dict) else None
99
+ if not (isinstance(context, str) and context.startswith("./services/")):
100
+ continue # infra (image:-based) service
101
+
102
+ # host_port = left side of the first "X:Y" ports mapping.
103
+ host_port = None
104
+ for mapping in spec.get("ports", []) or []:
105
+ left = str(mapping).split(":")[0]
106
+ if left.isdigit():
107
+ host_port = int(left)
108
+ break
109
+
110
+ # db_name from environment DB_NAME (supports list or dict form),
111
+ # default to the service key.
112
+ db_name = name
113
+ env = spec.get("environment")
114
+ env_pairs: dict[str, str] = {}
115
+ if isinstance(env, list):
116
+ for item in env:
117
+ if "=" in str(item):
118
+ k, v = str(item).split("=", 1)
119
+ env_pairs[k] = v
120
+ elif isinstance(env, dict):
121
+ env_pairs = {k: str(v) for k, v in env.items()}
122
+ if "DB_NAME" in env_pairs:
123
+ # value may be "${DB_NAME:-svc}"; take the default after :- if present.
124
+ raw = env_pairs["DB_NAME"]
125
+ if ":-" in raw:
126
+ db_name = raw.split(":-", 1)[1].rstrip("}")
127
+ elif not raw.startswith("$"):
128
+ db_name = raw
129
+
130
+ svc_type = _infer_type(name)
131
+ discovered.append(
132
+ {
133
+ "name": name,
134
+ "host_port": host_port,
135
+ "db_name": db_name,
136
+ # otel_name == compose service key == Go otelhttp.NewMiddleware name.
137
+ "otel_name": name,
138
+ "health_path": _health_path_for(svc_type),
139
+ "probe_path": _probe_path_for(svc_type),
140
+ "type": svc_type,
141
+ }
142
+ )
143
+ return discovered
144
+
145
+
146
+ @pytest.fixture(scope="session")
147
+ def services_manifest() -> list[dict]:
148
+ """Discovered APP services. Empty list is allowed (no services yet)."""
149
+ return _discover_services()
150
+
151
+
152
+ def _base_url(svc: dict) -> str:
153
+ return f"http://localhost:{svc['host_port']}"
154
+
155
+
156
+ @pytest.fixture(scope="session")
157
+ def cluster(services_manifest):
158
+ """Health-gate the dev stack: poll every discovered service's health
159
+ endpoint plus the jaeger query API. FAIL if REQUIRE_SERVICES and anything
160
+ is unreachable after the timeout; otherwise skip (local inner loop)."""
161
+
162
+ @retry(stop=stop_after_delay(300), wait=wait_exponential(multiplier=1, min=1, max=8))
163
+ def _wait():
164
+ unreachable = []
165
+ for svc in services_manifest:
166
+ if svc["host_port"] is None:
167
+ continue
168
+ url = f"{_base_url(svc)}{svc['health_path']}"
169
+ try:
170
+ r = httpx.get(url, timeout=2.0)
171
+ if r.status_code != 200:
172
+ unreachable.append(url)
173
+ except httpx.HTTPError:
174
+ unreachable.append(url)
175
+ try:
176
+ j = httpx.get(f"{JAEGER_URL}/api/services", timeout=2.0)
177
+ if j.status_code != 200:
178
+ unreachable.append(f"{JAEGER_URL}/api/services")
179
+ except httpx.HTTPError:
180
+ unreachable.append(f"{JAEGER_URL}/api/services")
181
+ if unreachable:
182
+ raise RuntimeError(f"unreachable: {unreachable}")
183
+
184
+ try:
185
+ _wait()
186
+ except (RetryError, RuntimeError) as exc:
187
+ if REQUIRE_SERVICES:
188
+ pytest.fail(
189
+ f"dev stack not healthy and GROUNDWORK_REQUIRE_SERVICES=1: {exc}"
190
+ )
191
+ pytest.skip(f"dev stack not reachable (run `./dev start`): {exc}")
192
+ return services_manifest
193
+
194
+
195
+ @pytest.fixture
196
+ def trace_id():
197
+ """A W3C trace id (32 hex chars)."""
198
+ return uuid.uuid4().hex
199
+
200
+
201
+ @pytest.fixture
202
+ async def api_client(trace_id):
203
+ """Async HTTPX client that stamps a W3C traceparent so test traffic is
204
+ identifiable in jaeger."""
205
+ span_id = uuid.uuid4().hex[:16]
206
+ traceparent = f"00-{trace_id}-{span_id}-01"
207
+ headers = {"traceparent": traceparent, "x-test-run": "system-test"}
208
+ async with httpx.AsyncClient(headers=headers, timeout=10.0) as client:
209
+ yield client
210
+
211
+
212
+ @pytest.fixture(scope="function", autouse=True)
213
+ def pure_state_reset(services_manifest):
214
+ """Truncate every table in each discovered service's database before each
215
+ test. Runs for BOTH system/ and bets/ suites (autouse is rootdir-scoped).
216
+ Tolerates a missing DB (not yet created) and an empty table set."""
217
+ for svc in services_manifest:
218
+ dsn = (
219
+ f"postgresql://{PG_USER}:{PG_PASSWORD}@{PG_HOST}:{PG_PORT}/{svc['db_name']}"
220
+ )
221
+ try:
222
+ with psycopg.connect(dsn, autocommit=True) as conn:
223
+ with conn.cursor() as cur:
224
+ cur.execute(
225
+ "SELECT tablename FROM pg_tables WHERE schemaname='public'"
226
+ )
227
+ tables = [row[0] for row in cur.fetchall()]
228
+ if tables:
229
+ joined = ", ".join(f'"{t}"' for t in tables)
230
+ cur.execute(
231
+ f"TRUNCATE {joined} RESTART IDENTITY CASCADE"
232
+ )
233
+ except psycopg.OperationalError:
234
+ pass # DB may not exist yet (pre-migrate); tolerate it.
235
+ yield
236
+
237
+
238
+ <% if (!surfaces && interfaceMedium === 'graphical-ui') { %>
239
+ @pytest.fixture(scope="session")
240
+ def frontend_base_url(services_manifest):
241
+ """Base URL for the Next.js frontend service. Used by graphical-ui bet-progress tests.
242
+
243
+ Discovers the first service of type 'next' from the workspace docker-compose.yml
244
+ and returns its host URL. Skips cleanly when no Next.js service is present.
245
+ """
246
+ next_svcs = [s for s in services_manifest if s.get("type") == "next"]
247
+ if not next_svcs:
248
+ pytest.skip("No Next.js service found in docker-compose.yml — frontend_base_url unavailable")
249
+ svc = next_svcs[0]
250
+ if svc["host_port"] is None:
251
+ pytest.skip(f"Next.js service '{svc['name']}' has no published host port")
252
+ return f"http://localhost:{svc['host_port']}"
253
+ <% } %><% if (surfaces) { %>
254
+ # ---------------------------------------------------------------------------
255
+ # Surface fixtures
256
+ #
257
+ # `surfaces` is the canonical per-surface reach map, derived from the surface
258
+ # registry (docs/surfaces.md / .groundwork/surfaces.json) at scaffold time.
259
+ # Per-surface runner fixtures are generated by test medium:
260
+ # playwright -> <slug>_page (Playwright page scoped to that surface)
261
+ # subprocess-cli -> <slug>_runner (invokes the binary, returns CompletedProcess)
262
+ # protocol-client -> <slug>_client (httpx client bound to the endpoint)
263
+ # flutter-integration -> <slug>_runner (drives the app's own integration_test
264
+ # suite as a subprocess via its Nx target)
265
+ # playwright-electron -> <slug>_runner (drives the app's own Playwright
266
+ # _electron smoke as a subprocess via its Nx target)
267
+ # A surface whose medium has no generated family (e.g. a scaffold: manual
268
+ # surface on bespoke tooling) is still registered in `surfaces` so tests can name it; the
269
+ # implementation must keep this registration honest when it lands — a health
270
+ # endpoint, ./dev integration, and a reach value tests can use.
271
+ # ---------------------------------------------------------------------------
272
+
273
+ # Scaffold-time surface specs. reach=None means "discover at runtime": URL
274
+ # mediums resolve the docker-compose service named after the slug.
275
+ _SURFACE_SPECS: dict[str, dict] = {
276
+ <% surfaces.forEach((s) => { %> "<%= s.slug %>": {"medium": "<%= s.medium %>", "reach": <%- s.reach ? JSON.stringify(s.reach) : 'None' %>},
277
+ <% }) %>}
278
+
279
+ _URL_MEDIUMS = {"playwright", "protocol-client"}
280
+ <% if (flutterSurfaces.length || electronSurfaces.length) { %>
281
+ # App-harness mediums -> the Nx target that runs the surface's OWN test suite.
282
+ # Their reach is a command (like subprocess-cli), not a URL: the suite, not
283
+ # this conftest, holds the Dart/Electron driver.
284
+ _HARNESS_MEDIUMS = {
285
+ "flutter-integration": "test-integration",
286
+ "playwright-electron": "smoke",
287
+ }
288
+ <% } %>
289
+
290
+ def _surface_reach(slug: str, spec: dict, manifest: list[dict]) -> str | None:
291
+ """Resolve a surface's reach: the scaffold-time value when set, otherwise
292
+ the compose service whose name matches the slug (URL mediums) or the
293
+ scaffolded app's Nx test target (app-harness mediums)."""
294
+ if spec["reach"] is not None:
295
+ return spec["reach"]
296
+ <% if (flutterSurfaces.length || electronSurfaces.length) { %> if spec["medium"] in _HARNESS_MEDIUMS:
297
+ if (SERVICES_DIR / slug / "project.json").exists():
298
+ return f"npx nx run {slug}:{_HARNESS_MEDIUMS[spec['medium']]}"
299
+ return None
300
+ <% } %> if spec["medium"] not in _URL_MEDIUMS:
301
+ return None
302
+ for svc in manifest:
303
+ if svc["name"] == slug and svc["host_port"] is not None:
304
+ return f"http://localhost:{svc['host_port']}"
305
+ <% if (graphicalSurfaces.length === 1) { %> # Single graphical surface: fall back to the first Next.js service — the
306
+ # same discovery the deprecated frontend_base_url fixture used.
307
+ if spec["medium"] == "playwright":
308
+ for svc in manifest:
309
+ if svc.get("type") == "next" and svc["host_port"] is not None:
310
+ return f"http://localhost:{svc['host_port']}"
311
+ <% } %> return None
312
+
313
+
314
+ @pytest.fixture(scope="session")
315
+ def surfaces(services_manifest) -> dict[str, dict]:
316
+ """Surface slug -> {"slug", "medium", "reach"} for every registered surface.
317
+
318
+ reach is a base URL for playwright/protocol-client surfaces, a launch
319
+ command for subprocess-cli surfaces, the test-harness command for
320
+ flutter-integration/playwright-electron surfaces, and None when the
321
+ surface is not reachable yet (its runner fixture skips).
322
+ """
323
+ return {
324
+ slug: {
325
+ "slug": slug,
326
+ "medium": spec["medium"],
327
+ "reach": _surface_reach(slug, spec, services_manifest),
328
+ }
329
+ for slug, spec in _SURFACE_SPECS.items()
330
+ }
331
+ <% graphicalSurfaces.forEach((s) => { %>
332
+
333
+ @pytest.fixture
334
+ def <%= s.ident %>_page(browser, surfaces):
335
+ """Playwright page for the `<%= s.slug %>` surface. Relative page.goto()
336
+ paths resolve against the surface's base URL."""
337
+ base = surfaces["<%= s.slug %>"]["reach"]
338
+ if base is None:
339
+ pytest.skip("surface '<%= s.slug %>' has no reachable base URL (is its service in docker-compose.yml?)")
340
+ context = browser.new_context(base_url=base)
341
+ page = context.new_page()
342
+ yield page
343
+ context.close()
344
+ <% }) %><% cliSurfaces.forEach((s) => { %>
345
+
346
+ @pytest.fixture
347
+ def <%= s.ident %>_runner(surfaces):
348
+ """Subprocess runner for the `<%= s.slug %>` CLI surface: run(args, ...) ->
349
+ subprocess.CompletedProcess. Drive interactive (REPL) flows with pexpect
350
+ against the same launch command."""
351
+ command = surfaces["<%= s.slug %>"]["reach"]
352
+ if command is None:
353
+ pytest.skip("surface '<%= s.slug %>' has no launch command registered")
354
+
355
+ def run(args, input=None, timeout=30, env=None):
356
+ cmd = [*shlex.split(command), *[str(a) for a in args]]
357
+ return subprocess.run(
358
+ cmd,
359
+ input=input,
360
+ capture_output=True,
361
+ text=True,
362
+ timeout=timeout,
363
+ env={**os.environ, **(env or {})},
364
+ )
365
+
366
+ return run
367
+ <% }) %><% protocolSurfaces.forEach((s) => { %>
368
+
369
+ @pytest.fixture
370
+ async def <%= s.ident %>_client(surfaces):
371
+ """Async httpx client bound to the `<%= s.slug %>` protocol endpoint."""
372
+ endpoint = surfaces["<%= s.slug %>"]["reach"]
373
+ if endpoint is None:
374
+ pytest.skip("surface '<%= s.slug %>' has no reachable endpoint (is its service in docker-compose.yml?)")
375
+ async with httpx.AsyncClient(base_url=endpoint, timeout=10.0) as client:
376
+ yield client
377
+ <% }) %><% if (flutterSurfaces.length || electronSurfaces.length) { %>
378
+
379
+ def _core_base_url(manifest: list[dict]) -> str | None:
380
+ """The capability core's gateway URL for app-harness surfaces: the compose
381
+ service named (or suffixed) `gateway` when one exists, otherwise the first
382
+ discovered service with a published port — the same booted topology the
383
+ API tests hit."""
384
+ candidates = [s for s in manifest if s["host_port"] is not None]
385
+ for svc in candidates:
386
+ if svc["name"] == "gateway" or svc["name"].endswith("-gateway"):
387
+ return _base_url(svc)
388
+ return _base_url(candidates[0]) if candidates else None
389
+
390
+
391
+ def _harness_runner(slug: str, command: str, *, default_args=(), default_env=None):
392
+ """Build a run() callable that drives a surface's OWN test harness as a
393
+ subprocess — the only honest integration this conftest can offer a Dart or
394
+ Electron suite, and what keeps the surface loop thin (prove-once: the
395
+ harness asserts wiring and rendering; capability behaviour is already
396
+ proven headless at the core's contract). Running through the app's Nx
397
+ target reuses its tool/*_exec.sh toolchain guard; a guard exit ("tier
398
+ skipped") becomes pytest.skip with the guard's reason — skipped with
399
+ reason, never silently green."""
400
+
401
+ def run(extra_args=(), timeout=900, env=None):
402
+ cmd = [*shlex.split(command), *[str(a) for a in (*default_args, *extra_args)]]
403
+ proc = subprocess.run(
404
+ cmd,
405
+ cwd=WORKSPACE_ROOT,
406
+ capture_output=True,
407
+ text=True,
408
+ timeout=timeout,
409
+ env={**os.environ, **(default_env or {}), **(env or {})},
410
+ )
411
+ if proc.returncode != 0 and "tier skipped" in (proc.stderr or ""):
412
+ pytest.skip(
413
+ f"surface '{slug}' harness unavailable — skipped, not silently "
414
+ f"green: {proc.stderr.strip()}"
415
+ )
416
+ return proc
417
+
418
+ return run
419
+ <% } %><% flutterSurfaces.forEach((s) => { %>
420
+
421
+ @pytest.fixture
422
+ def <%= s.ident %>_runner(surfaces, services_manifest):
423
+ """Flutter integration_test runner for the `<%= s.slug %>` mobile surface:
424
+ run(extra_args, ...) -> subprocess.CompletedProcess, driving the app's own
425
+ integration_test suite as a subprocess via its `test-integration` Nx
426
+ target. Prove-once: that suite asserts wiring and rendering only —
427
+ capability behaviour is already proven headless at the core's contract,
428
+ which is what keeps the expensive emulator loop thin. The core's gateway
429
+ URL is forwarded via --dart-define=API_BASE_URL so surface tests hit the
430
+ same booted topology the API tests use. Skips with reason when the Flutter
431
+ SDK or a device/emulator is unavailable — never silently green. Patrol is
432
+ the escalation path when a flow crosses the Flutter/OS boundary
433
+ (permission dialogs, push, system sheets); it is not wired here."""
434
+ command = surfaces["<%= s.slug %>"]["reach"]
435
+ if command is None:
436
+ pytest.skip("surface '<%= s.slug %>' has no test-harness command (is services/<%= s.slug %> scaffolded?)")
437
+ if shutil.which("flutter") is None:
438
+ pytest.skip(
439
+ "flutter SDK not found — '<%= s.slug %>' surface tier skipped, not "
440
+ "silently green (install the Flutter SDK, then `npx nx run <%= s.slug %>:bootstrap`)"
441
+ )
442
+ try:
443
+ probe = subprocess.run(
444
+ ["flutter", "devices", "--machine"],
445
+ capture_output=True,
446
+ text=True,
447
+ timeout=120,
448
+ )
449
+ devices = json.loads(probe.stdout or "[]")
450
+ except (OSError, subprocess.SubprocessError, ValueError):
451
+ devices = []
452
+ # Only platforms this app project supports count: a host machine usually
453
+ # reports desktop/web "devices" (macOS, Chrome) that `flutter test
454
+ # integration_test` cannot target for an android/ios scaffold — counting
455
+ # them turns the intended skip into a hard no-devices failure.
456
+ mobile_devices = [
457
+ d
458
+ for d in devices
459
+ if str(d.get("targetPlatform", "")).startswith(("android", "ios"))
460
+ ]
461
+ if not mobile_devices:
462
+ pytest.skip(
463
+ "no Android/iOS device or emulator available — '<%= s.slug %>' surface tier "
464
+ "skipped, not silently green (boot a headless Android emulator; "
465
+ "docs/principles/stack/flutter/testing.md)"
466
+ )
467
+ api_base = _core_base_url(services_manifest)
468
+ # `--` so Nx forwards the define verbatim to tool/flutter_exec.sh.
469
+ dart_defines = ["--", f"--dart-define=API_BASE_URL={api_base}"] if api_base else []
470
+ return _harness_runner("<%= s.slug %>", command, default_args=dart_defines)
471
+ <% }) %><% electronSurfaces.forEach((s) => { %>
472
+
473
+ @pytest.fixture
474
+ def <%= s.ident %>_runner(surfaces, services_manifest):
475
+ """Playwright _electron smoke runner for the `<%= s.slug %>` desktop surface:
476
+ run(extra_args, ...) -> subprocess.CompletedProcess, driving the app's own
477
+ Playwright _electron suite as a subprocess via its `smoke` Nx target.
478
+ Prove-once: that suite asserts boot, wiring, and rendering only —
479
+ capability behaviour is already proven headless at the core's contract.
480
+ tool/electron_exec.sh owns the toolchain question (Electron binary, xvfb
481
+ on displayless Linux); its guard exits are translated here into
482
+ pytest.skip with the guard's reason — never silently green. The core's
483
+ gateway URL is passed via the API_BASE_URL environment variable."""
484
+ command = surfaces["<%= s.slug %>"]["reach"]
485
+ if command is None:
486
+ pytest.skip("surface '<%= s.slug %>' has no test-harness command (is services/<%= s.slug %> scaffolded?)")
487
+ api_base = _core_base_url(services_manifest)
488
+ env = {"API_BASE_URL": api_base} if api_base else {}
489
+ return _harness_runner("<%= s.slug %>", command, default_env=env)
490
+ <% }) %><% if (graphicalSurfaces.length === 1) { %>
491
+
492
+ @pytest.fixture(scope="session")
493
+ def frontend_base_url(surfaces):
494
+ """DEPRECATED alias for surfaces["<%= graphicalSurfaces[0].slug %>"]["reach"].
495
+
496
+ Generated only while exactly one graphical surface exists; new tests read
497
+ the `surfaces` fixture instead.
498
+ """
499
+ base = surfaces["<%= graphicalSurfaces[0].slug %>"]["reach"]
500
+ if base is None:
501
+ pytest.skip("surface '<%= graphicalSurfaces[0].slug %>' has no reachable base URL — frontend_base_url unavailable")
502
+ return base
503
+ <% } %><% } %>
@@ -0,0 +1,20 @@
1
+ [project]
2
+ name = "tests"
3
+ version = "0.1.0"
4
+ description = "System Test Runner for <%= projectPrefix %>"
5
+ requires-python = ">=3.11"
6
+ dependencies = [
7
+ "pytest>=8.0.0",
8
+ "pytest-asyncio>=0.23.0",
9
+ "pytest-timeout>=2.3.1",
10
+ "httpx>=0.27.0",
11
+ "tenacity>=8.2.3",
12
+ "psycopg[binary]>=3.1.18",
13
+ "PyYAML>=6.0",<% if (includePlaywright) { %>
14
+ "pytest-playwright>=0.5",<% } %><% if (includePexpect) { %>
15
+ "pexpect>=4.9",<% } %>
16
+ ]
17
+
18
+ [tool.pytest.ini_options]
19
+ asyncio_mode = "auto"
20
+ testpaths = ["system", "bets"]
@@ -0,0 +1,9 @@
1
+ """Page objects for graphical-ui system tests.
2
+
3
+ Model each screen as a subclass of BasePage so selectors and navigation live
4
+ in one place instead of being repeated across tests.
5
+ """
6
+
7
+ from .base_page import BasePage
8
+
9
+ __all__ = ["BasePage"]
@@ -0,0 +1,36 @@
1
+ """Minimal page-object base for graphical-ui system tests.
2
+
3
+ Subclass per screen and add intent-named methods (e.g. submit_login) on top of
4
+ the shared navigation/assertion helpers here. <% if (!surfaces) { %>The frontend base URL comes from
5
+ the conftest `frontend_base_url` fixture, which discovers the Next.js service
6
+ from the workspace docker-compose.yml.<% } else { %>Each graphical surface's base URL
7
+ comes from the conftest `surfaces` fixture (slug -> reach).<% } %>
8
+ """
9
+
10
+ from playwright.sync_api import Page, expect
11
+
12
+
13
+ class BasePage:
14
+ """Holds the Playwright page plus the frontend base URL.
15
+
16
+ Helpers return self so page interactions chain:
17
+ <% if (!surfaces) { -%>
18
+ HomePage(page, frontend_base_url).goto("/").expect_visible("main")
19
+ <% } else { -%>
20
+ HomePage(page, surfaces["<%= graphicalSurfaces.length ? graphicalSurfaces[0].slug : 'web-app' %>"]["reach"]).goto("/").expect_visible("main")
21
+ <% } -%>
22
+ """
23
+
24
+ def __init__(self, page: Page, base_url: str):
25
+ self.page = page
26
+ self.base_url = base_url.rstrip("/")
27
+
28
+ def goto(self, path: str = "/") -> "BasePage":
29
+ """Navigate to a path under the frontend base URL and wait for load."""
30
+ self.page.goto(f"{self.base_url}{path}", wait_until="load")
31
+ return self
32
+
33
+ def expect_visible(self, selector: str, timeout_ms: float = 10_000) -> "BasePage":
34
+ """Assert the first element matching the selector is visible."""
35
+ expect(self.page.locator(selector).first).to_be_visible(timeout=timeout_ms)
36
+ return self