pyweb-stack 0.6.1__tar.gz → 0.6.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (370) hide show
  1. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/CHANGELOG.md +59 -0
  2. {pyweb_stack-0.6.1/pyweb_stack.egg-info → pyweb_stack-0.6.2}/PKG-INFO +15 -4
  3. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/README.md +14 -3
  4. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/THREAT_MODEL.md +15 -0
  5. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/01-introduction.md +4 -0
  6. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/02-quickstart.md +7 -1
  7. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/14-cli.md +14 -8
  8. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/16-limitations-roadmap.md +10 -6
  9. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/17-ai-assistants.md +20 -0
  10. pyweb_stack-0.6.2/docs/35-dev-loop.md +151 -0
  11. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyproject.toml +1 -1
  12. pyweb_stack-0.6.2/pyweb/_templates.py +18 -0
  13. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/app_loader.py +27 -2
  14. pyweb_stack-0.6.2/pyweb/assist.py +394 -0
  15. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/bench.py +33 -1
  16. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/cli/__init__.py +282 -20
  17. pyweb_stack-0.6.2/pyweb/compiler/diskcache.py +72 -0
  18. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/lower.py +2 -2
  19. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/parser.py +56 -0
  20. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/pipeline.py +16 -4
  21. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/devlink.py +37 -3
  22. pyweb_stack-0.6.2/pyweb/devopen.py +92 -0
  23. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/hosting.py +4 -3
  24. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/mcp.py +80 -0
  25. pyweb_stack-0.6.2/pyweb/qr.py +273 -0
  26. pyweb_stack-0.6.2/pyweb/runtime/browser/dev/assist.js +156 -0
  27. pyweb_stack-0.6.2/pyweb/runtime/browser/dev/inspect.js +138 -0
  28. pyweb_stack-0.6.2/pyweb/runtime/browser/dev/reload.js +180 -0
  29. pyweb_stack-0.6.2/pyweb/runtime/browser/dev/timeline.js +144 -0
  30. pyweb_stack-0.6.2/pyweb/runtime/browser/dev/welcome.js +46 -0
  31. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/runtime.js +4 -3
  32. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/server/__init__.py +2 -0
  33. pyweb_stack-0.6.2/pyweb/share.py +172 -0
  34. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/telemetry/devtools.py +4 -1
  35. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2/pyweb_stack.egg-info}/PKG-INFO +15 -4
  36. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb_stack.egg-info/SOURCES.txt +15 -0
  37. pyweb_stack-0.6.2/tests/test_assist.py +243 -0
  38. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_compile_cache.py +62 -1
  39. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_dev_reload.py +5 -3
  40. pyweb_stack-0.6.2/tests/test_devopen.py +87 -0
  41. pyweb_stack-0.6.2/tests/test_first_run.py +119 -0
  42. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_mcp.py +1 -1
  43. pyweb_stack-0.6.2/tests/test_qr.py +103 -0
  44. pyweb_stack-0.6.2/tests/test_share.py +153 -0
  45. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_trusted_types.py +8 -0
  46. pyweb_stack-0.6.1/pyweb/_templates.py +0 -3
  47. pyweb_stack-0.6.1/pyweb/runtime/browser/dev/reload.js +0 -102
  48. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/LICENSE +0 -0
  49. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/MANIFEST.in +0 -0
  50. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/03-tutorial.md +0 -0
  51. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/04-pyweb-files.md +0 -0
  52. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/05-reactivity.md +0 -0
  53. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/06-server-functions.md +0 -0
  54. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/07-browser-python.md +0 -0
  55. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/08-pages-routing-assets.md +0 -0
  56. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/09-data.md +0 -0
  57. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/10-auth.md +0 -0
  58. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/11-testing.md +0 -0
  59. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/12-deployment.md +0 -0
  60. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/13-security.md +0 -0
  61. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/15-toolkit.md +0 -0
  62. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/18-npm-packages.md +0 -0
  63. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/19-layouts-navigation.md +0 -0
  64. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/20-ai-apps.md +0 -0
  65. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/21-live-data.md +0 -0
  66. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/22-recipe-web3.md +0 -0
  67. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/23-forms.md +0 -0
  68. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/24-jobs.md +0 -0
  69. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/25-scaling.md +0 -0
  70. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/26-observability.md +0 -0
  71. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/27-upgrading.md +0 -0
  72. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/28-saas-tutorial.md +0 -0
  73. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/29-performance.md +0 -0
  74. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/30-teams.md +0 -0
  75. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/31-pwa-push.md +0 -0
  76. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/32-desktop.md +0 -0
  77. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/33-webhooks-files.md +0 -0
  78. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/docs/34-ui-and-motion.md +0 -0
  79. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/__init__.py +0 -0
  80. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/_speedups.py +0 -0
  81. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/a11y.py +0 -0
  82. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ai/guide.md +0 -0
  83. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/app.py +0 -0
  84. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/asgi.py +0 -0
  85. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/auth.py +0 -0
  86. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/__init__.py +0 -0
  87. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/admin.py +0 -0
  88. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/html.py +0 -0
  89. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/models.py +0 -0
  90. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/oauth.py +0 -0
  91. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/orgpages.py +0 -0
  92. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/orgs.py +0 -0
  93. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/pages.py +0 -0
  94. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/passwords.py +0 -0
  95. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/privacy.py +0 -0
  96. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/teams.py +0 -0
  97. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/throttle.py +0 -0
  98. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/tokens.py +0 -0
  99. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/authkit/webauthn.py +0 -0
  100. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/browser.py +0 -0
  101. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/build.py +0 -0
  102. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/cache.py +0 -0
  103. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/cli/__main__.py +0 -0
  104. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/__init__.py +0 -0
  105. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/ast.py +0 -0
  106. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/codegen/__init__.py +0 -0
  107. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/codegen/ir.py +0 -0
  108. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/errors.py +0 -0
  109. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/pyjs.py +0 -0
  110. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/compiler/rpc.py +0 -0
  111. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/config.py +0 -0
  112. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/context.py +0 -0
  113. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/csp_report.py +0 -0
  114. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/css.py +0 -0
  115. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/db/__init__.py +0 -0
  116. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/db/dialect.py +0 -0
  117. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/db/migrate.py +0 -0
  118. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/db/rls.py +0 -0
  119. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/db/schema.py +0 -0
  120. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/db/seeds.py +0 -0
  121. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/decorators.py +0 -0
  122. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/deploy/__init__.py +0 -0
  123. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/deploy/legacy.py +0 -0
  124. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/deploy/plan.py +0 -0
  125. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/deploy/targets.py +0 -0
  126. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/deprecation.py +0 -0
  127. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/desktop/__init__.py +0 -0
  128. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/desktop/gate.py +0 -0
  129. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/desktop/package.py +0 -0
  130. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/desktop/shell.py +0 -0
  131. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/doctor.py +0 -0
  132. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/dts.py +0 -0
  133. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/fieldcrypt.py +0 -0
  134. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/filegc.py +0 -0
  135. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/forms.py +0 -0
  136. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/http.py +0 -0
  137. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/__init__.py +0 -0
  138. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/builtin.py +0 -0
  139. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/core.py +0 -0
  140. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/db.py +0 -0
  141. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/legacy.py +0 -0
  142. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/memory.py +0 -0
  143. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/redis.py +0 -0
  144. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/schedule.py +0 -0
  145. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/jobs/worker.py +0 -0
  146. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/keys.py +0 -0
  147. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/livedata.py +0 -0
  148. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/livetable.py +0 -0
  149. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/lsp.py +0 -0
  150. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/lsp_data.py +0 -0
  151. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/lsp_teams.py +0 -0
  152. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/lsp_ui.py +0 -0
  153. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/mail.py +0 -0
  154. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/markdown.py +0 -0
  155. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/mcp_http.py +0 -0
  156. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/mcp_tools.py +0 -0
  157. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/models/__init__.py +0 -0
  158. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/models/fields.py +0 -0
  159. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/models/query.py +0 -0
  160. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/models/relations.py +0 -0
  161. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/motion.py +0 -0
  162. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/net/__init__.py +0 -0
  163. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/net/http.py +0 -0
  164. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/net/live.py +0 -0
  165. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/net/server.py +0 -0
  166. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/net/ws.py +0 -0
  167. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/observability.py +0 -0
  168. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/openapi.py +0 -0
  169. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/packages.py +0 -0
  170. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/platform.py +0 -0
  171. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/plugins.py +0 -0
  172. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/profile.py +0 -0
  173. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/push.py +0 -0
  174. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/pwa.py +0 -0
  175. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/py.typed +0 -0
  176. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/realtime.py +0 -0
  177. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/rooms.py +0 -0
  178. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/rpc.py +0 -0
  179. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/rules.py +0 -0
  180. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/auth.js +0 -0
  181. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/desktop.js +0 -0
  182. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/forms.js +0 -0
  183. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/live.js +0 -0
  184. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/markdown.js +0 -0
  185. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/motion-api.js +0 -0
  186. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/motion-count.js +0 -0
  187. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/motion-drag.js +0 -0
  188. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/motion-layout.js +0 -0
  189. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/motion-math.js +0 -0
  190. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/motion.js +0 -0
  191. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/pwa.js +0 -0
  192. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/sw.js +0 -0
  193. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/accordion.js +0 -0
  194. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/calendar.js +0 -0
  195. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/carousel.js +0 -0
  196. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/checkbox.js +0 -0
  197. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/collapsible.js +0 -0
  198. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/combobox.js +0 -0
  199. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/command.js +0 -0
  200. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/context-menu.js +0 -0
  201. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/core.js +0 -0
  202. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/dialog.js +0 -0
  203. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/hover-card.js +0 -0
  204. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/index.js +0 -0
  205. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/listbox.js +0 -0
  206. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/menu.js +0 -0
  207. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/menubar.js +0 -0
  208. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/navigation-menu.js +0 -0
  209. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/otp.js +0 -0
  210. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/popover.js +0 -0
  211. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/radio-group.js +0 -0
  212. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/resizable.js +0 -0
  213. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/select.js +0 -0
  214. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/sidebar.js +0 -0
  215. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/slider.js +0 -0
  216. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/tabs.js +0 -0
  217. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/toaster.js +0 -0
  218. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/toggle-group.js +0 -0
  219. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/toggle.js +0 -0
  220. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/browser/ui/tooltip.js +0 -0
  221. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/runtime/server/argcheck.py +0 -0
  222. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/sbom.py +0 -0
  223. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/secret_scan.py +0 -0
  224. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/security.py +0 -0
  225. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/serve.py +0 -0
  226. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ssr.py +0 -0
  227. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ssr_codegen.py +0 -0
  228. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/storage.py +0 -0
  229. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/sync.py +0 -0
  230. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/telemetry/__init__.py +0 -0
  231. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/telemetry/instruments.py +0 -0
  232. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/telemetry/logs.py +0 -0
  233. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/telemetry/metrics.py +0 -0
  234. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/telemetry/tracing.py +0 -0
  235. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/ai-chat.pyweb +0 -0
  236. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/app.css +0 -0
  237. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/auth.pyweb +0 -0
  238. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/blog.pyweb +0 -0
  239. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/chat.pyweb +0 -0
  240. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/counter.pyweb +0 -0
  241. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/desktop/app.pyweb +0 -0
  242. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/desktop/test_app.py +0 -0
  243. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/saas/app.pyweb +0 -0
  244. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/saas/seeds.py +0 -0
  245. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/saas/test_app.py +0 -0
  246. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/templates/todo.pyweb +0 -0
  247. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/tenancy.py +0 -0
  248. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/testing.py +0 -0
  249. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/__init__.py +0 -0
  250. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/cli.py +0 -0
  251. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/extending.py +0 -0
  252. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/button.pyweb +0 -0
  253. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/card.pyweb +0 -0
  254. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/carousel.pyweb +0 -0
  255. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/chart.pyweb +0 -0
  256. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/command.pyweb +0 -0
  257. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/controls.pyweb +0 -0
  258. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/data.pyweb +0 -0
  259. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/date.pyweb +0 -0
  260. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/dialog.pyweb +0 -0
  261. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/disclosure.pyweb +0 -0
  262. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/display.pyweb +0 -0
  263. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/layout.pyweb +0 -0
  264. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/menu.pyweb +0 -0
  265. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/overlay.pyweb +0 -0
  266. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/kit/style.pyweb +0 -0
  267. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/serve.py +0 -0
  268. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/source_edit.py +0 -0
  269. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/static/ui.css +0 -0
  270. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/ui/theme.py +0 -0
  271. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/upgrade.py +0 -0
  272. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/uploads.py +0 -0
  273. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb/webhooks.py +0 -0
  274. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb_stack.egg-info/dependency_links.txt +0 -0
  275. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb_stack.egg-info/entry_points.txt +0 -0
  276. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb_stack.egg-info/requires.txt +0 -0
  277. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/pyweb_stack.egg-info/top_level.txt +0 -0
  278. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/setup.cfg +0 -0
  279. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/setup.py +0 -0
  280. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_account_privacy.py +0 -0
  281. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_api_tokens.py +0 -0
  282. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_auth.py +0 -0
  283. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_auth_contract.py +0 -0
  284. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_auth_security.py +0 -0
  285. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_auth_sessions.py +0 -0
  286. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_auth_v1.py +0 -0
  287. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_authkit.py +0 -0
  288. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_authkit_units.py +0 -0
  289. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_backplane.py +0 -0
  290. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_browser_build.py +0 -0
  291. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_budget.py +0 -0
  292. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_cli_deploy.py +0 -0
  293. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_cli_test.py +0 -0
  294. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_codegen.py +0 -0
  295. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_compiler.py +0 -0
  296. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_cron.py +0 -0
  297. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_customise.py +0 -0
  298. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_data_layer.py +0 -0
  299. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_db_production.py +0 -0
  300. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_deploy_upload_render.py +0 -0
  301. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_deploy_v5.py +0 -0
  302. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_desktop.py +0 -0
  303. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_docs.py +0 -0
  304. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_doctor.py +0 -0
  305. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_dts.py +0 -0
  306. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_dx_v5.py +0 -0
  307. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_e2e.py +0 -0
  308. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_encrypted_fields.py +0 -0
  309. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_error_messages.py +0 -0
  310. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_examples.py +0 -0
  311. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_filegc.py +0 -0
  312. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_forms_security_obs.py +0 -0
  313. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_forms_v5.py +0 -0
  314. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_fuzz_requests.py +0 -0
  315. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_http_fetch.py +0 -0
  316. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_jobs_app.py +0 -0
  317. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_jobs_cache_realtime.py +0 -0
  318. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_jobs_v5.py +0 -0
  319. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_keys_sessions.py +0 -0
  320. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_live_patches.py +0 -0
  321. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_livedata.py +0 -0
  322. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_lsp.py +0 -0
  323. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_lsp_teams.py +0 -0
  324. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_markdown.py +0 -0
  325. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_mcp_teams.py +0 -0
  326. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_mcp_v6.py +0 -0
  327. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_migrations_property.py +0 -0
  328. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_migrations_v5.py +0 -0
  329. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_models_db.py +0 -0
  330. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_motion.py +0 -0
  331. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_multifile.py +0 -0
  332. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_multipage.py +0 -0
  333. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_net.py +0 -0
  334. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_observability.py +0 -0
  335. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_openapi.py +0 -0
  336. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_org_pages.py +0 -0
  337. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_packages.py +0 -0
  338. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_parser.py +0 -0
  339. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_parser_v1.py +0 -0
  340. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_plugins_platform_bench.py +0 -0
  341. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_production_gaps.py +0 -0
  342. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_profile.py +0 -0
  343. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_push.py +0 -0
  344. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_pwa.py +0 -0
  345. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_pyjs_semantics.py +0 -0
  346. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_rate_per_function.py +0 -0
  347. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_reactivity.py +0 -0
  348. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_realtime_transport.py +0 -0
  349. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_reference_apps.py +0 -0
  350. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_request_hardening.py +0 -0
  351. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_rpc_placement.py +0 -0
  352. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_rpc_production.py +0 -0
  353. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_runtime_signals.py +0 -0
  354. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_sbom.py +0 -0
  355. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_secret_scan.py +0 -0
  356. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_server_db.py +0 -0
  357. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_speedups.py +0 -0
  358. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_ssr_codegen.py +0 -0
  359. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_static_hashing.py +0 -0
  360. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_static_serving.py +0 -0
  361. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_streaming.py +0 -0
  362. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_sync_live.py +0 -0
  363. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_systems.py +0 -0
  364. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_telemetry.py +0 -0
  365. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_tenancy.py +0 -0
  366. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_testing_orgs.py +0 -0
  367. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_threat_model.py +0 -0
  368. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_ui_kit.py +0 -0
  369. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_webhooks.py +0 -0
  370. {pyweb_stack-0.6.1 → pyweb_stack-0.6.2}/tests/test_website.py +0 -0
@@ -6,6 +6,65 @@ project uses [semantic versioning](https://semver.org).
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.6.2]
10
+
11
+ The dev loop. Saves update the open page in place with every page and
12
+ component keeping its state, any element opens its own line in your
13
+ editor, error pages fix themselves with AI (your assistant's model through
14
+ MCP, or your own key), a timeline steps back through every change, and
15
+ `pyweb dev --share` gives someone a link to try what you're building. All
16
+ of it lives in `pyweb dev`: production output is unchanged and there is
17
+ nothing to change in your apps. See [The dev loop](docs/35-dev-loop.md).
18
+
19
+ ### Added
20
+ - **Hot reload without a page load.** A save swaps the page in place
21
+ through client navigation: no reload, no flash. Page variables,
22
+ component variables (each instance keeps its own), form fields, scroll,
23
+ focus and the selection stay. A stylesheet-only save swaps just that
24
+ stylesheet. When the page changed too much to swap, it reloads with the
25
+ same state, also after a compile error is fixed.
26
+ - **Click to source.** Hold Alt to see where any element comes from;
27
+ Alt-click opens that line in your editor (`PYWEB_EDITOR`, else VS Code,
28
+ Cursor, Windsurf, Zed or Sublime Text, else a `vscode://` link) and
29
+ shows the **inspector**: the components around it with their live
30
+ variables, which you can edit.
31
+ - **Fix with AI and Edit with AI.** Compile error pages and dev 500 pages
32
+ have Fix with AI; Alt+Shift-click any element to ask for a change. The
33
+ answer is a compiled diff of one app file: Apply writes it (refused if
34
+ the file changed since) and Undo puts it back (`.pyweb/history/`). It is
35
+ answered by the assistant connected through `pyweb mcp` when its app
36
+ supports MCP sampling, else `ANTHROPIC_API_KEY` or
37
+ `OPENAI_API_KEY`/`OPENAI_BASE_URL`, else the page offers the prompt to
38
+ copy. Credentials in what's sent are replaced by placeholders and put
39
+ back in the answer.
40
+ - **Time-travel timeline.** The toolbar's Timeline tab records every change
41
+ to the page's variables with its cause (a click, typing, a server call);
42
+ a slider steps back through them with the page paused, and Resume
43
+ returns to now.
44
+ - **`pyweb dev --share`**: a temporary public link (cloudflared, else
45
+ localhost.run) with a QR code. The link's token sets a cookie that every
46
+ request through the tunnel needs; guests get the app and hot reload, not
47
+ your tools.
48
+ - **A better first five minutes.** `pyweb new` with no name asks for the
49
+ name, a starter and a colour preset (`--theme` without asking); `pyweb
50
+ dev` opens the browser, prints the network URL with a QR code for a phone
51
+ with `--host 0.0.0.0`, and shows a one-time Welcome panel with what to
52
+ try and how to connect your assistant.
53
+ - **A faster first start.** Parse results and compiled code are cached on
54
+ disk (`~/.cache/pyweb`; `PYWEB_CACHE=0` turns it off): loading the saas
55
+ example in a fresh process went from about 340 to 210 ms.
56
+ `pyweb.bench --system` reports `cold_dev_ms`.
57
+ - MCP: the `pyweb_assist_requests` tool and the `fix_errors` prompt;
58
+ `pyweb mcp` answers the page's AI requests through sampling.
59
+
60
+ ### Changed
61
+ - `pyweb dev`'s toolbar and its `/__pyweb/dev/` endpoints answer only the
62
+ person running it: a request from this machine to a loopback address.
63
+ Visitors from the network (`--host 0.0.0.0`) or a share link get hot
64
+ reload only.
65
+ - The runtime is 25 bytes bigger (gzip) for the dev hooks; nothing runs
66
+ in production.
67
+
9
68
  ## [0.6.1]
10
69
 
11
70
  Better error messages, `pyweb doctor`, a `pyweb dev` that keeps your place
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyweb-stack
3
- Version: 0.6.1
3
+ Version: 0.6.2
4
4
  Summary: Full-stack web apps in one Python file: server-rendered pages, reactive browser UI, typed RPC.
5
5
  Author-email: MaanavKrishna <67054795+MaanavKrishna@users.noreply.github.com>
6
6
  Maintainer-email: MaanavKrishna <67054795+MaanavKrishna@users.noreply.github.com>
@@ -400,6 +400,17 @@ develop a toolbar on every page shows each request's queries and flags
400
400
  N+1 loops. [Scaling & deploying →](docs/25-scaling.md) ·
401
401
  [Logs, metrics & tracing →](docs/26-observability.md)
402
402
 
403
+ ### A dev loop that keeps up
404
+
405
+ Save, and the open page changes in place: no reload, and every page and
406
+ component keeps its state. Hold Alt and click any element to open its
407
+ line in your editor; Alt+Shift-click to change it with AI, and error
408
+ pages have **Fix with AI** (your assistant's model through MCP, or your
409
+ own API key), with a diff to apply and Undo. The toolbar's timeline
410
+ steps back through every change and what caused it, and
411
+ `pyweb dev --share` gives someone a link to try what you're building.
412
+ [The dev loop →](docs/35-dev-loop.md)
413
+
403
414
  ### Small, fast and boring to run
404
415
 
405
416
  - **Every page is server-rendered**: complete HTML on first paint, then
@@ -442,7 +453,7 @@ it runs the real PyWeb, server functions included, in your browser.
442
453
  pip install pyweb-stack
443
454
  pyweb new myapp --template saas # saas | desktop | blank | counter | todo | blog | auth | chat | ai-chat
444
455
  cd myapp
445
- pyweb dev app.pyweb # edit app.pyweb; the page reloads on save
456
+ pyweb dev app.pyweb # saves update the open page in place, state kept
446
457
  ```
447
458
 
448
459
  Then:
@@ -478,7 +489,7 @@ The [architecture overview](ARCHITECTURE.md) goes through each stage.
478
489
 
479
490
  ## Build it with AI
480
491
 
481
- PyWeb ships an MCP server with 30 tools, so AI assistants can do what
492
+ PyWeb ships an MCP server with 31 tools, so AI assistants can do what
482
493
  you'd do: scaffold an app, search the docs, check each edit (errors come
483
494
  back as line numbers with fix hints), build with the UI kit and a theme,
484
495
  render pages and call server functions as any signed-in member, look at
@@ -566,7 +577,7 @@ Upgrade with `pip install -U pyweb-stack`.
566
577
 
567
578
  | Version | Highlights |
568
579
  |---|---|
569
- | 0.6 | Teams with roles, invitations and tenant-scoped Models (Postgres row-level security), API tokens and OpenAPI, webhooks, installable apps with Web Push, desktop windows and installers, a UI kit with themes and motion, Trusted Types, encrypted fields and a threat model, about 2.5× faster serving, Python 3.15 and free-threaded builds, a much richer MCP server; 0.6.1: error messages with code frames and suggestions, `pyweb doctor`, dev reloads that keep page state, 4× faster reloads and tests |
580
+ | 0.6 | Teams with roles, invitations and tenant-scoped Models (Postgres row-level security), API tokens and OpenAPI, webhooks, installable apps with Web Push, desktop windows and installers, a UI kit with themes and motion, Trusted Types, encrypted fields and a threat model, about 2.5× faster serving, Python 3.15 and free-threaded builds, a much richer MCP server; 0.6.1: error messages with code frames and suggestions, `pyweb doctor`, dev reloads that keep page state, 4× faster reloads and tests; 0.6.2: the dev loop (hot reload in place with component state, Alt-click to source, Fix/Edit with AI, a time-travel timeline, `pyweb dev --share`, a guided `pyweb new`) |
570
581
  | 0.5 | Models with migrations, forms, auth kit with passkeys, OAuth and an admin, row-level live updates over WebSockets on PyWeb's own server, durable jobs and schedules, `pyweb deploy` for docker, compose, k8s, fly, render and railway, logs, metrics, tracing and a dev toolbar, data-aware editor and MCP tools, the `saas` template, `pyweb upgrade` |
571
582
  | 0.4 | npm packages without Node, layouts and client-side navigation, streaming server functions and `<Markdown>` for AI apps, live queries, page head tags, `.pyweb` error pages; 0.4.1: richer MCP tools; 0.4.2: VS Code run, new-app and MCP commands; 0.4.3: fixes, security hardening, gzip and caching; 0.4.4: key rotation, session revocation, typed arguments, Redis-shared limits, `check --production` |
572
583
  | 0.3 | Hydration, live updates (SSE), multi-file apps, language server + VS Code extension, browser playground, faster rendering, screenshot/test MCP tools |
@@ -326,6 +326,17 @@ develop a toolbar on every page shows each request's queries and flags
326
326
  N+1 loops. [Scaling & deploying →](docs/25-scaling.md) ·
327
327
  [Logs, metrics & tracing →](docs/26-observability.md)
328
328
 
329
+ ### A dev loop that keeps up
330
+
331
+ Save, and the open page changes in place: no reload, and every page and
332
+ component keeps its state. Hold Alt and click any element to open its
333
+ line in your editor; Alt+Shift-click to change it with AI, and error
334
+ pages have **Fix with AI** (your assistant's model through MCP, or your
335
+ own API key), with a diff to apply and Undo. The toolbar's timeline
336
+ steps back through every change and what caused it, and
337
+ `pyweb dev --share` gives someone a link to try what you're building.
338
+ [The dev loop →](docs/35-dev-loop.md)
339
+
329
340
  ### Small, fast and boring to run
330
341
 
331
342
  - **Every page is server-rendered**: complete HTML on first paint, then
@@ -368,7 +379,7 @@ it runs the real PyWeb, server functions included, in your browser.
368
379
  pip install pyweb-stack
369
380
  pyweb new myapp --template saas # saas | desktop | blank | counter | todo | blog | auth | chat | ai-chat
370
381
  cd myapp
371
- pyweb dev app.pyweb # edit app.pyweb; the page reloads on save
382
+ pyweb dev app.pyweb # saves update the open page in place, state kept
372
383
  ```
373
384
 
374
385
  Then:
@@ -404,7 +415,7 @@ The [architecture overview](ARCHITECTURE.md) goes through each stage.
404
415
 
405
416
  ## Build it with AI
406
417
 
407
- PyWeb ships an MCP server with 30 tools, so AI assistants can do what
418
+ PyWeb ships an MCP server with 31 tools, so AI assistants can do what
408
419
  you'd do: scaffold an app, search the docs, check each edit (errors come
409
420
  back as line numbers with fix hints), build with the UI kit and a theme,
410
421
  render pages and call server functions as any signed-in member, look at
@@ -492,7 +503,7 @@ Upgrade with `pip install -U pyweb-stack`.
492
503
 
493
504
  | Version | Highlights |
494
505
  |---|---|
495
- | 0.6 | Teams with roles, invitations and tenant-scoped Models (Postgres row-level security), API tokens and OpenAPI, webhooks, installable apps with Web Push, desktop windows and installers, a UI kit with themes and motion, Trusted Types, encrypted fields and a threat model, about 2.5× faster serving, Python 3.15 and free-threaded builds, a much richer MCP server; 0.6.1: error messages with code frames and suggestions, `pyweb doctor`, dev reloads that keep page state, 4× faster reloads and tests |
506
+ | 0.6 | Teams with roles, invitations and tenant-scoped Models (Postgres row-level security), API tokens and OpenAPI, webhooks, installable apps with Web Push, desktop windows and installers, a UI kit with themes and motion, Trusted Types, encrypted fields and a threat model, about 2.5× faster serving, Python 3.15 and free-threaded builds, a much richer MCP server; 0.6.1: error messages with code frames and suggestions, `pyweb doctor`, dev reloads that keep page state, 4× faster reloads and tests; 0.6.2: the dev loop (hot reload in place with component state, Alt-click to source, Fix/Edit with AI, a time-travel timeline, `pyweb dev --share`, a guided `pyweb new`) |
496
507
  | 0.5 | Models with migrations, forms, auth kit with passkeys, OAuth and an admin, row-level live updates over WebSockets on PyWeb's own server, durable jobs and schedules, `pyweb deploy` for docker, compose, k8s, fly, render and railway, logs, metrics, tracing and a dev toolbar, data-aware editor and MCP tools, the `saas` template, `pyweb upgrade` |
497
508
  | 0.4 | npm packages without Node, layouts and client-side navigation, streaming server functions and `<Markdown>` for AI apps, live queries, page head tags, `.pyweb` error pages; 0.4.1: richer MCP tools; 0.4.2: VS Code run, new-app and MCP commands; 0.4.3: fixes, security hardening, gzip and caching; 0.4.4: key rotation, session revocation, typed arguments, Redis-shared limits, `check --production` |
498
509
  | 0.3 | Hydration, live updates (SSE), multi-file apps, language server + VS Code extension, browser playground, faster rendering, screenshot/test MCP tools |
@@ -177,6 +177,21 @@ websites in the user's browser.
177
177
  | T | An assistant's "read-only" SQL changing data | One statement, write keywords refused (even in a CTE), a read-only transaction that is rolled back; secrets redacted | `test_dx_v5.py::test_mcp_data_tools` |
178
178
  | T | Malformed tool arguments reaching app code | Arguments are checked against each tool's schema before it runs | `test_mcp_v6.py::test_arguments_are_checked_before_the_tool_runs` |
179
179
 
180
+ ## 7d. The dev loop: sharing, AI help, open in editor
181
+
182
+ `pyweb dev` only. Its tools change files, open programs and show request data, so they are for the
183
+ person running it, on that machine: a request must come from a loopback address and name a loopback
184
+ `Host` (a tunnel's or the LAN's requests don't), and writes must be same-origin.
185
+
186
+ | | Threat | Mitigation | Proof |
187
+ |---|---|---|---|
188
+ | S | Someone who learns the `--share` address (or guesses the tunnel name) using the app | Every request through the tunnel needs a cookie (`HttpOnly`, `Secure`, `SameSite=Lax`) set by the printed link's random token; forged cookies are refused | `test_share.py::test_the_link_sets_a_cookie_and_nothing_else_gets_in`, `test_share.py::test_pyweb_dev_share_end_to_end` |
189
+ | E/I | A share-link guest (or someone on the LAN) using the developer's tools: the toolbar's SQL and requests, the agent endpoints, AI fixes, opening files, saving the theme | Guests get the app and hot reload only; every `/__pyweb/dev/` endpoint but change polling answers 403 to them, and their pages carry no toolbar or tool scripts | `test_share.py::test_guests_get_the_app_and_hot_reload_only`, `test_share.py::test_you_still_get_everything_and_the_lan_gets_hot_reload`, `test_share.py::test_a_compile_error_page_for_guests_has_no_tools` |
190
+ | T | A web page making "Fix with AI" or "Edit with AI" write to the app | Same-origin, loopback-only POSTs; the answer is compiled first, applied only on Apply, only to `.pyweb` files in the app, refused if the file changed since; the old version is kept for Undo | `test_assist.py::test_endpoints_refuse_other_sites_and_other_machines`, `test_assist.py::test_a_change_that_does_not_compile_is_refused`, `test_assist.py::test_apply_refuses_when_the_file_changed_since`, `test_assist.py::test_only_app_files_are_targets` |
191
+ | I | Credentials in the app's source sent to a model | Known key formats and random-looking secret values are replaced by placeholders before sending and put back in the answer | `test_assist.py::test_secrets_are_replaced_before_sending_and_put_back`, `test_assist.py::test_the_connected_assistant_answers_through_mcp_sampling` |
192
+ | E | Alt-click "open in editor" used to open arbitrary files or run commands | Only `.pyweb` files inside the app folder or the UI kit; the editor gets an argument list, never a shell; same-origin and loopback only | `test_devopen.py::test_only_app_and_kit_files_resolve`, `e2e/test_dev_inspect_browser.py::test_open_refuses_cross_site_and_outside_files` |
193
+ | I | Dev-only markers or scripts in production pages | `data-pw-src` markers come from dev compiles only; the dev scripts are added by the dev server only | `test_devopen.py::test_other_builds_have_no_marks`, `test_trusted_types.py::test_dev_scripts_never_ship_in_built_pages` |
194
+
180
195
  ## 8. The release
181
196
 
182
197
  | | Threat | Mitigation | Proof |
@@ -43,6 +43,10 @@ Around that core, PyWeb has what a product needs, in the same file:
43
43
  ([Installable apps](31-pwa-push.md), [Desktop apps](32-desktop.md))
44
44
  - **Webhooks and files**: signed webhooks in and out, and unused uploads
45
45
  cleaned up. ([Webhooks & files](33-webhooks-files.md))
46
+ - **A dev loop that keeps up**: saves update the open page in place with
47
+ its state kept; Alt-click opens any element's source; Fix with AI and
48
+ Edit with AI; a time-travel timeline; `pyweb dev --share`.
49
+ ([The dev loop](35-dev-loop.md))
46
50
  - **Shipping**: `pyweb deploy` writes Docker, Compose, Kubernetes, Fly,
47
51
  Render or Railway files; logs, metrics and traces come built in.
48
52
  ([Scaling & deploying](25-scaling.md))
@@ -20,9 +20,14 @@ pip install "pyweb-stack[all]" # optional: Postgres, MySQL, Redis, argon2, O
20
20
  ```bash
21
21
  pyweb new hello
22
22
  cd hello
23
- pyweb dev app.pyweb # http://localhost:8000, reloads on save
23
+ pyweb dev app.pyweb # opens http://localhost:8000; saves update the page in place
24
24
  ```
25
25
 
26
+ (`pyweb new` with no name asks for one, a starter and colours.) Save a
27
+ change and the open page updates without losing its state; hold Alt and
28
+ click anything to open its line in your editor. [The dev loop](35-dev-loop.md)
29
+ has the rest: Fix with AI, time travel and sharing with `--share`.
30
+
26
31
  `pyweb new` writes `app.pyweb`, a starter test (`test_app.py`) and
27
32
  `AGENTS.md`/`CLAUDE.md` (instructions for AI coding agents). Add
28
33
  `--template saas` for a small product with teams, accounts, a database,
@@ -107,6 +112,7 @@ ships it. Then, depending on what you're building:
107
112
  - work that runs later or on a schedule: [Background jobs](24-jobs.md);
108
113
  - teams that share data: [Teams & organizations](30-teams.md);
109
114
  - components, a theme and animation: [UI kit & motion](34-ui-and-motion.md);
115
+ - everything `pyweb dev` does for you: [The dev loop](35-dev-loop.md);
110
116
  - an app people install, or a desktop app: [Installable apps & push](31-pwa-push.md),
111
117
  [Desktop apps](32-desktop.md);
112
118
  - several pages with a shared header: [Layouts & navigation](19-layouts-navigation.md);
@@ -1,15 +1,21 @@
1
1
  # Command line
2
2
 
3
3
  ```text
4
- pyweb new NAME [--template T] create NAME/ with app.pyweb, test_app.py, AGENTS.md, CLAUDE.md, static/;
4
+ pyweb new [NAME] [--template T] [--theme PRESET]
5
+ create NAME/ with app.pyweb, test_app.py, AGENTS.md, CLAUDE.md, static/;
5
6
  T = blank | counter (default) | todo | blog | saas | auth | chat | ai-chat | desktop
6
- (apps with a database also get migrations/0001_initial.py and a README)
7
- pyweb dev FILE [--port 8000] [--host 127.0.0.1] [--no-reload]
8
- development server: recompile on save, live reload that keeps the
9
- page's variables, form fields, scroll and focus (add ?fresh to
10
- the URL to start over), error overlay,
11
- the dev toolbar (requests, SQL, jobs, emails, theme and motion
12
- editors), and background jobs in the same process; writes
7
+ (apps with a database also get migrations/0001_initial.py and a README);
8
+ PRESET = indigo | zinc | slate | rose | ocean | violet | emerald | amber
9
+ (written into App(theme=...)); with no NAME, in a terminal, it asks
10
+ pyweb dev FILE [--port 8000] [--host 127.0.0.1] [--no-reload] [--no-open] [--share]
11
+ development server (see The dev loop): saves update the open page
12
+ in place, keeping page and component state (?fresh starts over);
13
+ Alt-click opens an element's line in your editor, Alt+Shift-click
14
+ changes it with AI, error pages have Fix with AI; the dev toolbar
15
+ (requests, SQL, jobs, emails, theme, motion, a time-travel timeline);
16
+ background jobs in the same process; opens the browser (not in CI,
17
+ over SSH or with --no-open); --host 0.0.0.0 prints the network URL
18
+ with a QR code; --share prints a temporary public link; writes
13
19
  .pyweb/dev.json so `pyweb mcp` can see its errors and logs
14
20
  pyweb check FILE [--production] [--strict]
15
21
  compile, security and accessibility checks; --production also checks
@@ -11,9 +11,9 @@ can decide up front whether they matter for your app.
11
11
  - **npm packages must ship ES modules.** CommonJS-only packages and
12
12
  packages built on Node.js modules can't run in the browser; see
13
13
  [npm packages](18-npm-packages.md).
14
- - **Dev reload keeps page variables, not component state.** After a save,
15
- `pyweb dev` reloads the page with its variables, form fields, scroll
16
- and focus as they were; state inside components starts over.
14
+ - **Time travel moves the page's state only.** The dev timeline puts the
15
+ page's and components' variables back; data on the server isn't
16
+ rolled back.
17
17
  - **SQLite is for one machine.** Several processes on one host share it
18
18
  fine, but more than one server needs Postgres or MySQL;
19
19
  `pyweb check --production` and `pyweb deploy` say so.
@@ -36,7 +36,11 @@ can decide up front whether they matter for your app.
36
36
  faster serving, Python 3.15 and free-threaded builds, and a much richer
37
37
  MCP server. 0.6.1 added error messages with code frames and
38
38
  suggestions, `pyweb doctor`, dev reloads that keep page state, and 4×
39
- faster reloads and tests.
39
+ faster reloads and tests. 0.6.2 made the [dev loop](35-dev-loop.md):
40
+ saves update the page in place with component state kept, Alt-click
41
+ opens any element's source, Fix with AI and Edit with AI, a
42
+ time-travel timeline, `pyweb dev --share`, a faster first start and a
43
+ guided `pyweb new`.
40
44
  - **0.5**: production apps. Models with relations and migrations, forms
41
45
  checked in the browser and on the server, an auth kit (passwords,
42
46
  passkeys, emailed links, OAuth, two-step sign-in, an admin), row-level
@@ -67,8 +71,8 @@ Planned, roughly in order. Nothing here is promised for a date.
67
71
  1. **1.0**: the API, RPC protocol and CLI frozen under semantic versioning,
68
72
  after 0.6 has been used in production for a while.
69
73
  2. **File uploads from the playground and the admin.**
70
- 3. **Hot reload without a page reload** while developing (0.6.1 already
71
- keeps the page's variables, fields, scroll and focus across reloads).
74
+ 3. **Fix with AI in the editor**, from the same proposals the dev page
75
+ shows (diff, apply, undo), through the VS Code extension.
72
76
 
73
77
  Ideas, bug reports and pull requests are welcome; see
74
78
  [CONTRIBUTING.md](https://github.com/MaanavKrishna/PyWeb/blob/main/CONTRIBUTING.md).
@@ -108,6 +108,7 @@ tool runs. Slow tools (tests, screenshots, profiling) report progress.
108
108
  | `pyweb_dev` | Whether `pyweb dev` is running for this app: its URL, whether the app compiles right now (with the error and traceback), its pages and recent 500 errors. |
109
109
  | `pyweb_doctor` | Project health, as `pyweb doctor`: each check with `status` (ok, warn, fail), `detail` and a `fix`; `production=true` adds the production settings. |
110
110
  | `pyweb_logs` | The dev server's log lines (warnings, errors with tracebacks, slow queries, job failures); `since` returns only newer ones. |
111
+ | `pyweb_assist_requests` | What the developer asked for from the page (Fix with AI on an error page, Alt+Shift-click → Edit with AI) while no AI was set up to answer: the file, the error or the element's line, and the instruction. |
111
112
 
112
113
  When `pyweb dev` starts, it writes `.pyweb/dev.json` next to the app: its
113
114
  address and a random token, readable only by you (the folder has its own
@@ -149,6 +150,7 @@ Prompts are step-by-step workflows that name the tools to use:
149
150
  | `design_pass` | Kit components, a theme and motion, reviewed in light, dark and on a phone. |
150
151
  | `fix_failing_test` | Reproduce, find the cause in the app, fix, re-run. |
151
152
  | `debug_page` | Errors, logs, requests and a profile for one page. |
153
+ | `fix_errors` | Check, fix and test in a loop until the app compiles cleanly and the tests pass; first does what was asked from the page. |
152
154
 
153
155
  ### What a session looks like
154
156
 
@@ -172,6 +174,24 @@ Prompts are step-by-step workflows that name the tools to use:
172
174
  click around, the assistant reads the error with `pyweb_dev` and
173
175
  `pyweb_logs` and fixes it.
174
176
 
177
+ ### Fix with AI from the page (sampling)
178
+
179
+ `pyweb dev` puts a **Fix with AI** button on error pages, and
180
+ Alt+Shift-click asks for a change to any element (see
181
+ [The dev loop](35-dev-loop.md#fix-with-ai-and-edit-with-ai)). When your
182
+ assistant's app supports MCP **sampling** (the client lets a server ask
183
+ its model a question, after you approve), `pyweb mcp` answers those
184
+ requests with your assistant's own model: it notices the client offers
185
+ sampling when it connects, finds the running `pyweb dev` through
186
+ `.pyweb/dev.json`, and hands each request over. The page shows the
187
+ answer as a diff to apply or discard. This works over stdio (`pyweb
188
+ mcp`); set `PYWEB_APP` when the app file isn't `app.pyweb` in the folder
189
+ the assistant starts in.
190
+
191
+ Assistants without sampling see the same requests with
192
+ `pyweb_assist_requests` and can do them with their own file tools; the
193
+ `fix_errors` prompt starts there.
194
+
175
195
  `pyweb_render`, `pyweb_call`, `pyweb_screenshot`, `pyweb_review`,
176
196
  `pyweb_profile`, `pyweb_webhook_send`, `pyweb_jobs` and `pyweb_test` run
177
197
  your app's code, as `pyweb dev` or `pytest` would; `pyweb_packages`
@@ -0,0 +1,151 @@
1
+ # The dev loop
2
+
3
+ `pyweb dev app.pyweb` is where you spend your day, so it does a lot for
4
+ you: saves show up in the open page without a reload, any element opens
5
+ its own line in your editor, errors come with a "Fix with AI" button, you
6
+ can step back through what the page did, and a link lets someone else
7
+ try what you're building. Everything on this page exists only under
8
+ `pyweb dev`: production builds, `pyweb serve` and `TestClient` are
9
+ unchanged.
10
+
11
+ ## Your first run
12
+
13
+ ```bash
14
+ pyweb new # in a terminal: asks for a name, a starter and colours
15
+ cd my-app
16
+ pyweb dev app.pyweb # opens the browser
17
+ ```
18
+
19
+ `pyweb new` with no name asks three questions: the folder name, a
20
+ starter (each with a line saying what it is) and a colour preset, which
21
+ it writes into `App(theme=Theme(...))`. `pyweb new shop --template todo
22
+ --theme rose` does the same without asking.
23
+
24
+ `pyweb dev` opens your browser (not in CI, over SSH, or with
25
+ `--no-open`) and, the first time a project runs, shows a short Welcome
26
+ panel: what to try, and the snippet that connects your AI assistant.
27
+ **Got it** hides it for good (`PYWEB_WELCOME=0` turns it off).
28
+
29
+ ## Saves update the page in place
30
+
31
+ Change some markup, a style or a function and save. The open page
32
+ updates in about a tenth of a second, without a reload and without a
33
+ flash:
34
+
35
+ - **page and component state stays.** Every page variable and every
36
+ component's variables keep their values; two `<Counter />`s keep their
37
+ own counts. A variable you renamed, or whose type changed (a number
38
+ that is now a string), starts over.
39
+ - **form fields, scroll position, focus and the text selection stay**,
40
+ for fields that have an `id` or a `name`.
41
+ - **a stylesheet-only save** swaps that stylesheet and nothing else.
42
+
43
+ When the page's structure changed too much to swap in place (a new
44
+ layout, different npm packages), it reloads, and the same state comes
45
+ back. After a compile error the browser shows the error; fix it, save,
46
+ and you're back where you were, state included. Add `?fresh` to the URL
47
+ to start over every time.
48
+
49
+ The first start is fast too: parse results and compiled code are kept in
50
+ `~/.cache/pyweb` (`PYWEB_CACHE_DIR` to move it, `PYWEB_CACHE=0` to turn
51
+ it off), keyed by each file's contents and the PyWeb and Python versions.
52
+
53
+ ## Alt-click to open the source
54
+
55
+ Hold **Alt** (Option on a Mac) and point at anything: it is outlined,
56
+ with the components it sits in and its file and line. **Alt-click** it
57
+ to open that line in your editor. It also opens the **inspector**: the
58
+ chain of components around the element, each with its live variables.
59
+ Type a new value (JSON: `3`, `"hi"`, `[1, 2]`) and the page follows.
60
+
61
+ The editor is `$PYWEB_EDITOR` when you set it, a command with `{file}`
62
+ and `{line}` in it:
63
+
64
+ ```bash
65
+ export PYWEB_EDITOR='code -g {file}:{line}' # VS Code
66
+ export PYWEB_EDITOR='idea --line {line} {file}' # JetBrains
67
+ export PYWEB_EDITOR='nvim +{line} {file}' # in a terminal editor, use a new window
68
+ ```
69
+
70
+ Otherwise the first of VS Code (`code`), Cursor, Windsurf, Zed and
71
+ Sublime Text found on your `PATH`; with none of them, the inspector shows
72
+ a `vscode://` link. Elements that come from the UI kit open the line in
73
+ your app that uses them.
74
+
75
+ ## Fix with AI, and Edit with AI
76
+
77
+ When the app doesn't compile, or a page fails with an exception, the
78
+ error page has a **Fix with AI** button. **Alt+Shift-click** any element
79
+ to say what should change ("make this a card with a delete button").
80
+
81
+ Either way you get a **diff** of one file in your app, already compiled:
82
+ a change that doesn't compile is shown but can't be applied. **Apply**
83
+ writes it (only if the file hasn't changed since), the page updates in
84
+ place, and **Undo** puts the old version back (every replaced version is
85
+ also kept in `.pyweb/history/`).
86
+
87
+ Who answers, in this order:
88
+
89
+ 1. **Your assistant, through `pyweb mcp`.** If the assistant's app
90
+ supports MCP *sampling*, `pyweb mcp` hands the request to it: its own
91
+ model does the work, and the app asks you before each request.
92
+ 2. **An API key** in the environment `pyweb dev` runs in:
93
+ `ANTHROPIC_API_KEY`, or `OPENAI_API_KEY` / `OPENAI_BASE_URL` (any
94
+ OpenAI-compatible server, Ollama included), with `AI_MODEL` to choose
95
+ the model.
96
+ 3. **Nobody yet.** The page gives you the prompt to copy into any
97
+ assistant, and a connected assistant can pick the request up with the
98
+ `pyweb_assist_requests` tool (the `fix_errors` prompt starts there).
99
+
100
+ What's sent is the file and the error (or your instruction). Credentials
101
+ in them, in the formats `pyweb check` knows and random-looking values in
102
+ secret-named variables, are replaced by placeholders before sending and
103
+ put back in the answer.
104
+
105
+ ## Time travel
106
+
107
+ The toolbar's **Timeline** tab (the ⚡ badge, bottom left) records every
108
+ change to the page's variables with what caused it: a click on which
109
+ button, typing in which field, Enter, a server function call. Each event
110
+ is one step. Drag the slider, press **Step back** or click a step and
111
+ every variable goes back to its value then; the page is paused while you
112
+ look (clicks and typing are held back). **Resume** puts the latest values
113
+ back. Only the page's own state moves: data on the server isn't rolled
114
+ back. The last 500 changes are kept.
115
+
116
+ ## On your phone, and with someone else
117
+
118
+ ```bash
119
+ pyweb dev app.pyweb --host 0.0.0.0 # prints the network URL and a QR code
120
+ pyweb dev app.pyweb --share # a temporary public link (and a QR code)
121
+ ```
122
+
123
+ `--host 0.0.0.0` listens on your network: scan the QR code with a phone
124
+ on the same Wi-Fi.
125
+
126
+ `--share` starts a tunnel, with `cloudflared` when it's installed or
127
+ `ssh` to localhost.run otherwise, and prints a link like
128
+ `https://quiet-fox-12.trycloudflare.com/__pyweb/share?t=…`. Anyone with
129
+ the link can use the app and sees your saves live. Nobody gets in with
130
+ the address alone: the link's token sets a cookie, and every other
131
+ request through the tunnel is refused. The link works until you stop
132
+ `pyweb dev`.
133
+
134
+ People on the network or coming through a share link get the app and
135
+ hot reload, never your tools: no toolbar (it shows SQL and request
136
+ data), inspector, AI help, editor opening or theme saving. Those
137
+ answer only requests from your machine to `localhost`.
138
+
139
+ ## Security limits
140
+
141
+ | Feature | Who can use it |
142
+ |---|---|
143
+ | Hot reload, the error page | Everyone who can open the page |
144
+ | Toolbar, timeline, inspector, Alt-click, Fix/Edit with AI, theme saving, Welcome | You: a request from this machine, to a loopback address, from the page itself |
145
+ | Files AI may change | `.pyweb` files inside the app folder; only after Apply; never if the file changed since |
146
+ | Files Alt-click may open | `.pyweb` files in the app folder or in PyWeb's UI kit |
147
+ | `--share` guests | The app, with the link's cookie; nothing under `/__pyweb/dev/` but change polling |
148
+ | `pyweb mcp`'s view of the dev server | With the token in `.pyweb/dev.json` (readable by you only), from this machine |
149
+
150
+ The [threat model](https://github.com/MaanavKrishna/PyWeb/blob/main/THREAT_MODEL.md) lists each of these with the tests
151
+ that prove it.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyweb-stack"
7
- version = "0.6.1"
7
+ version = "0.6.2"
8
8
  description = "Full-stack web apps in one Python file: server-rendered pages, reactive browser UI, typed RPC."
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -0,0 +1,18 @@
1
+ """The `pyweb new` template names (kept apart so the CLI can list them without loading the MCP server)."""
2
+
3
+ TEMPLATES = ("blank", "counter", "todo", "blog", "saas", "auth", "chat", "ai-chat", "desktop")
4
+
5
+ # The colour presets `pyweb new --theme` offers (pyweb.ui.theme.PRESETS has their values; a test keeps the two in step).
6
+ THEME_PRESETS = ("indigo", "zinc", "slate", "rose", "ocean", "violet", "emerald", "amber")
7
+
8
+ DESCRIPTIONS = {
9
+ "blank": "one empty page",
10
+ "counter": "a page with a button: the smallest app with state",
11
+ "todo": "a list you add to and tick off, with the UI kit",
12
+ "blog": "pages with routes, a database and server functions",
13
+ "saas": "teams, sign-in, data, background jobs and an admin",
14
+ "auth": "accounts: sign up, sign in, passkeys",
15
+ "chat": "a live chat room (realtime)",
16
+ "ai-chat": "a streaming chat with an AI model",
17
+ "desktop": "a notes app in its own window",
18
+ }
@@ -51,6 +51,8 @@ def _module_code(source, filename, infos):
51
51
  import hashlib
52
52
  key = (filename, hashlib.sha256(source.encode()).hexdigest(), tuple(getattr(i, "name", "") for i in infos))
53
53
  code = _CODE.get(key)
54
+ if code is None:
55
+ code = _disk_code(key)
54
56
  if code is None:
55
57
  py_source, _ui = P.split_sources(source)
56
58
  tree = ast.parse(py_source, filename=filename)
@@ -60,9 +62,32 @@ def _module_code(source, filename, infos):
60
62
  if len(_CODE) > 256:
61
63
  _CODE.clear()
62
64
  _CODE[key] = code
65
+ _disk_code(key, code)
66
+ elif key not in _CODE:
67
+ _CODE[key] = code
63
68
  return code
64
69
 
65
70
 
71
+ def _disk_code(key, code=None):
72
+ """Read (or with ``code``, write) a module's code object in the on-disk cache."""
73
+ import marshal
74
+
75
+ from .compiler import diskcache
76
+ if not diskcache.enabled():
77
+ return None
78
+ k = diskcache.key("code", key[0], key[1], *key[2])
79
+ if code is not None:
80
+ diskcache.put("code", k, marshal.dumps(code))
81
+ return code
82
+ data = diskcache.get("code", k)
83
+ if data is None:
84
+ return None
85
+ try:
86
+ return marshal.loads(data)
87
+ except Exception: # noqa: BLE001 - a corrupt entry: compile again
88
+ return None
89
+
90
+
66
91
  def _kit_markup(path):
67
92
  """Whether a component file is kit markup (a component copied with ``pyweb ui add``)."""
68
93
  try:
@@ -75,7 +100,7 @@ def _kit_markup(path):
75
100
 
76
101
  class LoadedApp:
77
102
  def __init__(self, path=None, *, source=None, filename=None, asset_urls=None,
78
- stylesheets=None):
103
+ stylesheets=None, dev=False):
79
104
  if source is None:
80
105
  with open(path, encoding="utf-8") as fh:
81
106
  source = fh.read()
@@ -84,7 +109,7 @@ class LoadedApp:
84
109
  self.source = source
85
110
  self.asset_urls = dict(asset_urls or {})
86
111
  self.extra_stylesheets = list(stylesheets or [])
87
- self.compiled = compile_source(source, filename=self.filename)
112
+ self.compiled = compile_source(source, filename=self.filename, dev=dev)
88
113
  self.ctx = self.compiled["context"]
89
114
  # Other .pyweb files the app imports run as real modules, registered
90
115
  # under their import name so `from widgets import Card` works.