groundwork-method 0.0.1 → 0.10.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 (629) hide show
  1. package/CHANGELOG.md +781 -0
  2. package/LICENSE +21 -0
  3. package/README.md +44 -29
  4. package/bin/groundwork.js +1654 -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 +125 -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 +68 -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 +82 -0
  106. package/src/docs/principles/index.md +23 -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 +118 -0
  128. package/src/engineer-skills/groundwork-electron-engineer/references/ipc-contracts.md +138 -0
  129. package/src/engineer-skills/groundwork-electron-engineer/references/packaging-and-updates.md +82 -0
  130. package/src/engineer-skills/groundwork-electron-engineer/references/process-model.md +94 -0
  131. package/src/engineer-skills/groundwork-electron-engineer/references/security.md +107 -0
  132. package/src/engineer-skills/groundwork-electron-engineer/references/testing-and-smoke.md +107 -0
  133. package/src/engineer-skills/groundwork-electron-engineer/references/theming-and-tokens.md +74 -0
  134. package/src/engineer-skills/groundwork-electron-engineer/sync-anchor.md +14 -0
  135. package/src/engineer-skills/groundwork-flutter-engineer/SKILL.md +108 -0
  136. package/src/engineer-skills/groundwork-flutter-engineer/references/accessibility.md +92 -0
  137. package/src/engineer-skills/groundwork-flutter-engineer/references/architecture.md +189 -0
  138. package/src/engineer-skills/groundwork-flutter-engineer/references/data-and-contracts.md +136 -0
  139. package/src/engineer-skills/groundwork-flutter-engineer/references/navigation.md +122 -0
  140. package/src/engineer-skills/groundwork-flutter-engineer/references/platform-channels.md +93 -0
  141. package/src/engineer-skills/groundwork-flutter-engineer/references/releases-and-distribution.md +84 -0
  142. package/src/engineer-skills/groundwork-flutter-engineer/references/state-management.md +166 -0
  143. package/src/engineer-skills/groundwork-flutter-engineer/references/testing.md +135 -0
  144. package/src/engineer-skills/groundwork-flutter-engineer/references/theming-and-design-tokens.md +109 -0
  145. package/src/engineer-skills/groundwork-flutter-engineer/references/widgets-and-composition.md +123 -0
  146. package/src/engineer-skills/groundwork-flutter-engineer/sync-anchor.md +15 -0
  147. package/src/engineer-skills/groundwork-go-engineer/SKILL.md +171 -0
  148. package/src/engineer-skills/groundwork-go-engineer/references/api-design.md +82 -0
  149. package/src/engineer-skills/groundwork-go-engineer/references/architecture.md +42 -0
  150. package/src/engineer-skills/groundwork-go-engineer/references/capability-ports.md +50 -0
  151. package/src/engineer-skills/groundwork-go-engineer/references/code-craft-security.md +34 -0
  152. package/src/engineer-skills/groundwork-go-engineer/references/concurrency.md +108 -0
  153. package/src/engineer-skills/groundwork-go-engineer/references/go-services.md +77 -0
  154. package/src/engineer-skills/groundwork-go-engineer/references/http-handlers.md +172 -0
  155. package/src/engineer-skills/groundwork-go-engineer/references/implementation-patterns.md +156 -0
  156. package/src/engineer-skills/groundwork-go-engineer/references/integration-realtime-data.md +57 -0
  157. package/src/engineer-skills/groundwork-go-engineer/references/observability.md +49 -0
  158. package/src/engineer-skills/groundwork-go-engineer/references/postgres.md +41 -0
  159. package/src/engineer-skills/groundwork-go-engineer/references/reliability-performance.md +105 -0
  160. package/src/engineer-skills/groundwork-go-engineer/references/testing.md +139 -0
  161. package/src/engineer-skills/groundwork-go-engineer/sync-anchor.md +11 -0
  162. package/src/engineer-skills/groundwork-nextjs-engineer/SKILL.md +107 -0
  163. package/src/engineer-skills/groundwork-nextjs-engineer/references/architecture.md +323 -0
  164. package/src/engineer-skills/groundwork-nextjs-engineer/references/data-fetching.md +458 -0
  165. package/src/engineer-skills/groundwork-nextjs-engineer/references/documentation.md +324 -0
  166. package/src/engineer-skills/groundwork-nextjs-engineer/references/error-boundaries.md +383 -0
  167. package/src/engineer-skills/groundwork-nextjs-engineer/references/mutations-and-forms.md +396 -0
  168. package/src/engineer-skills/groundwork-nextjs-engineer/references/performance-and-deployment.md +947 -0
  169. package/src/engineer-skills/groundwork-nextjs-engineer/references/routing-and-navigation.md +405 -0
  170. package/src/engineer-skills/groundwork-nextjs-engineer/references/server-components.md +394 -0
  171. package/src/engineer-skills/groundwork-nextjs-engineer/references/tailwind-and-styling.md +134 -0
  172. package/src/engineer-skills/groundwork-nextjs-engineer/references/testing.md +433 -0
  173. package/src/engineer-skills/groundwork-nextjs-engineer/references/type-system.md +368 -0
  174. package/src/engineer-skills/groundwork-nextjs-engineer/references/ux-principles.md +278 -0
  175. package/src/engineer-skills/groundwork-nextjs-engineer/references/visual-language.md +69 -0
  176. package/src/engineer-skills/groundwork-nextjs-engineer/sync-anchor.md +9 -0
  177. package/src/engineer-skills/groundwork-python-engineer/SKILL.md +196 -0
  178. package/src/engineer-skills/groundwork-python-engineer/references/api-standards.md +88 -0
  179. package/src/engineer-skills/groundwork-python-engineer/references/architecture.md +57 -0
  180. package/src/engineer-skills/groundwork-python-engineer/references/async-patterns.md +103 -0
  181. package/src/engineer-skills/groundwork-python-engineer/references/capability-ports.md +44 -0
  182. package/src/engineer-skills/groundwork-python-engineer/references/database.md +88 -0
  183. package/src/engineer-skills/groundwork-python-engineer/references/documentation-mcp.md +167 -0
  184. package/src/engineer-skills/groundwork-python-engineer/references/implementation-patterns.md +166 -0
  185. package/src/engineer-skills/groundwork-python-engineer/references/ml-pipelines.md +119 -0
  186. package/src/engineer-skills/groundwork-python-engineer/references/ml-systems-ai-engineering.md +74 -0
  187. package/src/engineer-skills/groundwork-python-engineer/references/observability.md +57 -0
  188. package/src/engineer-skills/groundwork-python-engineer/references/resilience.md +126 -0
  189. package/src/engineer-skills/groundwork-python-engineer/references/testing.md +177 -0
  190. package/src/engineer-skills/groundwork-python-engineer/sync-anchor.md +13 -0
  191. package/src/generators/add-capability/generator.ts +70 -0
  192. package/src/generators/add-capability/schema.json +30 -0
  193. package/src/generators/capabilities/llm/capability.json +28 -0
  194. package/src/generators/capabilities/llm/providers/anthropic/footprint.json +13 -0
  195. package/src/generators/capabilities/llm/providers/anthropic/stacks/go/internal/llm/llm.go.template +102 -0
  196. package/src/generators/capabilities/llm/providers/anthropic/stacks/python/src/__packageName__/adapters/llm.py.template +61 -0
  197. package/src/generators/capabilities/llm/providers/local/footprint.json +13 -0
  198. package/src/generators/capabilities/llm/providers/local/stacks/go/internal/llm/llm.go.template +102 -0
  199. package/src/generators/capabilities/llm/providers/local/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  200. package/src/generators/capabilities/llm/providers/localai/footprint.json +29 -0
  201. package/src/generators/capabilities/llm/providers/localai/stacks/go/internal/llm/llm.go.template +102 -0
  202. package/src/generators/capabilities/llm/providers/localai/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  203. package/src/generators/capabilities/llm/providers/none/footprint.json +9 -0
  204. package/src/generators/capabilities/llm/providers/none/stacks/go/internal/llm/llm.go.template +35 -0
  205. package/src/generators/capabilities/llm/providers/none/stacks/python/src/__packageName__/adapters/llm.py.template +25 -0
  206. package/src/generators/capabilities/llm/providers/ollama/footprint.json +20 -0
  207. package/src/generators/capabilities/llm/providers/ollama/stacks/go/internal/llm/llm.go.template +102 -0
  208. package/src/generators/capabilities/llm/providers/ollama/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  209. package/src/generators/capabilities/llm/providers/openai/footprint.json +13 -0
  210. package/src/generators/capabilities/llm/providers/openai/stacks/go/internal/llm/llm.go.template +98 -0
  211. package/src/generators/capabilities/llm/providers/openai/stacks/python/src/__packageName__/adapters/llm.py.template +60 -0
  212. package/src/generators/capabilities/llm/stacks/go/internal/core/service/llm.go.template +12 -0
  213. package/src/generators/capabilities/llm/stacks/go/internal/llm/llm_test.go.template +33 -0
  214. package/src/generators/capabilities/llm/stacks/python/src/__packageName__/core/llm.py.template +15 -0
  215. package/src/generators/capabilities/llm/stacks/python/tests/contracts/test_llm.py.template +37 -0
  216. package/src/generators/cli-app/files/README.md.template +76 -0
  217. package/src/generators/cli-app/files/build.mjs.template +15 -0
  218. package/src/generators/cli-app/files/package.json.template +21 -0
  219. package/src/generators/cli-app/files/src/cli.ts.template +67 -0
  220. package/src/generators/cli-app/files/src/commands/hello.ts.template +17 -0
  221. package/src/generators/cli-app/files/src/commands/status.ts.template +23 -0
  222. package/src/generators/cli-app/files/src/core/client.test.ts.template +80 -0
  223. package/src/generators/cli-app/files/src/core/client.ts.template +64 -0
  224. package/src/generators/cli-app/files/src/registry.test.ts.template +35 -0
  225. package/src/generators/cli-app/files/src/registry.ts.template +31 -0
  226. package/src/generators/cli-app/files/tsconfig.json.template +16 -0
  227. package/src/generators/cli-app/files/tsconfig.test.json.template +11 -0
  228. package/src/generators/cli-app/generator.ts +138 -0
  229. package/src/generators/cli-app/schema.json +24 -0
  230. package/src/generators/docs-site/files/.gitignore.ejs +40 -0
  231. package/src/generators/docs-site/files/app/docs/__slug__/page.tsx +101 -0
  232. package/src/generators/docs-site/files/app/docs/layout.tsx +14 -0
  233. package/src/generators/docs-site/files/app/docs.css +43 -0
  234. package/src/generators/docs-site/files/app/layout.tsx +24 -0
  235. package/src/generators/docs-site/files/app/page.tsx +135 -0
  236. package/src/generators/docs-site/files/app/source.ts +8 -0
  237. package/src/generators/docs-site/files/components/mermaid.tsx +67 -0
  238. package/src/generators/docs-site/files/next.config.mjs +10 -0
  239. package/src/generators/docs-site/files/package.json +32 -0
  240. package/src/generators/docs-site/files/pnpm-workspace.yaml +7 -0
  241. package/src/generators/docs-site/files/postcss.config.mjs +6 -0
  242. package/src/generators/docs-site/files/source.config.ts +77 -0
  243. package/src/generators/docs-site/files/tailwind.config.js +10 -0
  244. package/src/generators/docs-site/files/tsconfig.json +27 -0
  245. package/src/generators/docs-site/generator.ts +476 -0
  246. package/src/generators/docs-site/schema.json +17 -0
  247. package/src/generators/electron-app/docs/principles/stack/electron/index.md +47 -0
  248. package/src/generators/electron-app/docs/principles/stack/electron/ipc-contracts.md +71 -0
  249. package/src/generators/electron-app/docs/principles/stack/electron/packaging-and-updates.md +59 -0
  250. package/src/generators/electron-app/docs/principles/stack/electron/process-model.md +53 -0
  251. package/src/generators/electron-app/docs/principles/stack/electron/security.md +70 -0
  252. package/src/generators/electron-app/docs/principles/stack/typescript/frontend.md +65 -0
  253. package/src/generators/electron-app/files/.gitignore.template +20 -0
  254. package/src/generators/electron-app/files/README.md.template +125 -0
  255. package/src/generators/electron-app/files/electron.vite.config.ts +31 -0
  256. package/src/generators/electron-app/files/eslint.config.mjs +92 -0
  257. package/src/generators/electron-app/files/forge.config.ts.template +44 -0
  258. package/src/generators/electron-app/files/package.json.template +54 -0
  259. package/src/generators/electron-app/files/playwright.config.ts +18 -0
  260. package/src/generators/electron-app/files/project.json.template +65 -0
  261. package/src/generators/electron-app/files/src/main/core-client.test.ts +81 -0
  262. package/src/generators/electron-app/files/src/main/core-client.ts +55 -0
  263. package/src/generators/electron-app/files/src/main/index.ts +157 -0
  264. package/src/generators/electron-app/files/src/main/ipc.ts +52 -0
  265. package/src/generators/electron-app/files/src/main/policy.test.ts +71 -0
  266. package/src/generators/electron-app/files/src/main/policy.ts +73 -0
  267. package/src/generators/electron-app/files/src/preload/index.ts +23 -0
  268. package/src/generators/electron-app/files/src/renderer/index.html.template +20 -0
  269. package/src/generators/electron-app/files/src/renderer/src/App.test.tsx +61 -0
  270. package/src/generators/electron-app/files/src/renderer/src/App.tsx.template +43 -0
  271. package/src/generators/electron-app/files/src/renderer/src/assets/main.css +40 -0
  272. package/src/generators/electron-app/files/src/renderer/src/env.d.ts +14 -0
  273. package/src/generators/electron-app/files/src/renderer/src/main.tsx +25 -0
  274. package/src/generators/electron-app/files/src/shared/ipc.ts +54 -0
  275. package/src/generators/electron-app/files/tests/smoke/app.spec.ts.template +68 -0
  276. package/src/generators/electron-app/files/tool/electron_exec.sh.template +83 -0
  277. package/src/generators/electron-app/files/tsconfig.json +7 -0
  278. package/src/generators/electron-app/files/tsconfig.node.json +27 -0
  279. package/src/generators/electron-app/files/tsconfig.web.json +22 -0
  280. package/src/generators/electron-app/files/vitest.config.ts +32 -0
  281. package/src/generators/electron-app/files/vitest.setup.ts +1 -0
  282. package/src/generators/electron-app/generator.ts +288 -0
  283. package/src/generators/electron-app/schema.json +23 -0
  284. package/src/generators/flutter-app/docs/principles/stack/flutter/architecture.md +78 -0
  285. package/src/generators/flutter-app/docs/principles/stack/flutter/index.md +38 -0
  286. package/src/generators/flutter-app/docs/principles/stack/flutter/platform-channels.md +51 -0
  287. package/src/generators/flutter-app/docs/principles/stack/flutter/releases-and-distribution.md +59 -0
  288. package/src/generators/flutter-app/docs/principles/stack/flutter/state-management.md +85 -0
  289. package/src/generators/flutter-app/docs/principles/stack/flutter/testing.md +74 -0
  290. package/src/generators/flutter-app/docs/principles/stack/flutter/widgets-and-composition.md +69 -0
  291. package/src/generators/flutter-app/files/.gitignore.template +30 -0
  292. package/src/generators/flutter-app/files/README.md.template +100 -0
  293. package/src/generators/flutter-app/files/analysis_options.yaml.template +18 -0
  294. package/src/generators/flutter-app/files/integration_test/app_test.dart.template +30 -0
  295. package/src/generators/flutter-app/files/lib/app.dart.template +24 -0
  296. package/src/generators/flutter-app/files/lib/config/app_config.dart +15 -0
  297. package/src/generators/flutter-app/files/lib/data/repositories/status_repository.dart +36 -0
  298. package/src/generators/flutter-app/files/lib/data/services/api_client.dart +71 -0
  299. package/src/generators/flutter-app/files/lib/domain/models/health_status.dart +23 -0
  300. package/src/generators/flutter-app/files/lib/main.dart +11 -0
  301. package/src/generators/flutter-app/files/lib/router.dart +23 -0
  302. package/src/generators/flutter-app/files/lib/ui/core/theme/app_theme.dart +110 -0
  303. package/src/generators/flutter-app/files/lib/ui/home/home_view.dart +89 -0
  304. package/src/generators/flutter-app/files/lib/ui/home/home_view_model.dart.template +38 -0
  305. package/src/generators/flutter-app/files/project.json.template +51 -0
  306. package/src/generators/flutter-app/files/pubspec.yaml.template +47 -0
  307. package/src/generators/flutter-app/files/test/api_client_test.dart.template +63 -0
  308. package/src/generators/flutter-app/files/test/fakes/fake_status_repository.dart.template +19 -0
  309. package/src/generators/flutter-app/files/test/home_view_test.dart.template +58 -0
  310. package/src/generators/flutter-app/files/tool/flutter_exec.sh.template +60 -0
  311. package/src/generators/flutter-app/generator.ts +362 -0
  312. package/src/generators/flutter-app/schema.json +23 -0
  313. package/src/generators/go-microservice/docs/principles/stack/go/concurrency.md +123 -0
  314. package/src/generators/go-microservice/docs/principles/stack/go/index.md +70 -0
  315. package/src/generators/go-microservice/docs/principles/stack/go/testing.md +152 -0
  316. package/src/generators/go-microservice/files/.air.toml.template +38 -0
  317. package/src/generators/go-microservice/files/.env.template +4 -0
  318. package/src/generators/go-microservice/files/.golangci.yml.template +82 -0
  319. package/src/generators/go-microservice/files/Dockerfile.dev.template +12 -0
  320. package/src/generators/go-microservice/files/asyncapi-pubsub.yaml.template +33 -0
  321. package/src/generators/go-microservice/files/asyncapi-ws.yaml.template +34 -0
  322. package/src/generators/go-microservice/files/cmd/api/main.go.template +149 -0
  323. package/src/generators/go-microservice/files/cmd/api/main_test.go.template +99 -0
  324. package/src/generators/go-microservice/files/cmd/worker/cleanup/main.go.template +39 -0
  325. package/src/generators/go-microservice/files/db/schema.sql.template +24 -0
  326. package/src/generators/go-microservice/files/go.mod.template +39 -0
  327. package/src/generators/go-microservice/files/internal/config/config.go.template +52 -0
  328. package/src/generators/go-microservice/files/internal/config/otel.go.template +93 -0
  329. package/src/generators/go-microservice/files/internal/core/domain/errors.go.template +16 -0
  330. package/src/generators/go-microservice/files/internal/core/domain/model.go.template +28 -0
  331. package/src/generators/go-microservice/files/internal/core/domain/user.go.template +13 -0
  332. package/src/generators/go-microservice/files/internal/core/pagination.go.template +16 -0
  333. package/src/generators/go-microservice/files/internal/core/service/app_service.go.template +79 -0
  334. package/src/generators/go-microservice/files/internal/core/service/event_hub.go.template +9 -0
  335. package/src/generators/go-microservice/files/internal/core/service/message_queue.go.template +10 -0
  336. package/src/generators/go-microservice/files/internal/core/service/outbox_repository.go.template +31 -0
  337. package/src/generators/go-microservice/files/internal/core/service/repository.go.template +23 -0
  338. package/src/generators/go-microservice/files/internal/core/service/user_repository.go.template +15 -0
  339. package/src/generators/go-microservice/files/internal/core/service/user_service.go.template +43 -0
  340. package/src/generators/go-microservice/files/internal/entrypoints/api/app_handler.go.template +108 -0
  341. package/src/generators/go-microservice/files/internal/entrypoints/api/auth_middleware_test.go.template +52 -0
  342. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook.go.template +202 -0
  343. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook_test.go.template +82 -0
  344. package/src/generators/go-microservice/files/internal/entrypoints/api/health_handler.go.template +80 -0
  345. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware.go.template +87 -0
  346. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware_test.go.template +76 -0
  347. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/repository.go.template +37 -0
  348. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_auth.go.template +40 -0
  349. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_loadshed.go.template +38 -0
  350. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_logging.go.template +40 -0
  351. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_ratelimit.go.template +48 -0
  352. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_test.go.template +81 -0
  353. package/src/generators/go-microservice/files/internal/entrypoints/api/router.go.template +105 -0
  354. package/src/generators/go-microservice/files/internal/entrypoints/api/types.go.template +70 -0
  355. package/src/generators/go-microservice/files/internal/entrypoints/api/websocket_handler.go.template +39 -0
  356. package/src/generators/go-microservice/files/internal/httpclient/http_client.go.template +87 -0
  357. package/src/generators/go-microservice/files/internal/kafka/kafka.go.template +34 -0
  358. package/src/generators/go-microservice/files/internal/postgres/postgres.go.template +195 -0
  359. package/src/generators/go-microservice/files/internal/postgres/postgres_test.go.template +156 -0
  360. package/src/generators/go-microservice/files/internal/postgres/user_repository.go.template +56 -0
  361. package/src/generators/go-microservice/files/internal/pubsub/gcp_pubsub.go.template +35 -0
  362. package/src/generators/go-microservice/files/internal/websocket/client.go.template +151 -0
  363. package/src/generators/go-microservice/files/internal/websocket/hub.go.template +261 -0
  364. package/src/generators/go-microservice/files/scripts/apply-schema.sh.template +21 -0
  365. package/src/generators/go-microservice/files/tools/tools.go.template +10 -0
  366. package/src/generators/go-microservice/generator.ts +240 -0
  367. package/src/generators/go-microservice/schema.json +63 -0
  368. package/src/generators/nextjs-app/docs/principles/stack/typescript/frontend.md +65 -0
  369. package/src/generators/nextjs-app/files/.dockerignore.template +7 -0
  370. package/src/generators/nextjs-app/files/.env.example.template +24 -0
  371. package/src/generators/nextjs-app/files/.gitignore.template +5 -0
  372. package/src/generators/nextjs-app/files/Dockerfile +53 -0
  373. package/src/generators/nextjs-app/files/app/(auth)/sign-in/__sign-in__/page.tsx.template +9 -0
  374. package/src/generators/nextjs-app/files/app/(auth)/sign-up/__sign-up__/page.tsx.template +9 -0
  375. package/src/generators/nextjs-app/files/app/api/config/route.ts.template +39 -0
  376. package/src/generators/nextjs-app/files/app/api/healthz/route.test.ts +15 -0
  377. package/src/generators/nextjs-app/files/app/api/healthz/route.ts +5 -0
  378. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.test.ts.template +55 -0
  379. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.ts.template +126 -0
  380. package/src/generators/nextjs-app/files/app/error.tsx +39 -0
  381. package/src/generators/nextjs-app/files/app/global-error.tsx +68 -0
  382. package/src/generators/nextjs-app/files/app/globals.css +105 -0
  383. package/src/generators/nextjs-app/files/app/layout.tsx +59 -0
  384. package/src/generators/nextjs-app/files/app/loading.tsx +13 -0
  385. package/src/generators/nextjs-app/files/app/not-found.tsx +30 -0
  386. package/src/generators/nextjs-app/files/app/page.tsx +20 -0
  387. package/src/generators/nextjs-app/files/components/providers/default.tsx +19 -0
  388. package/src/generators/nextjs-app/files/components/providers/production.tsx +32 -0
  389. package/src/generators/nextjs-app/files/components/providers/telemetry.tsx +76 -0
  390. package/src/generators/nextjs-app/files/components/render-smoke.test.tsx +29 -0
  391. package/src/generators/nextjs-app/files/components/theme-provider.tsx +11 -0
  392. package/src/generators/nextjs-app/files/components.json +21 -0
  393. package/src/generators/nextjs-app/files/eslint.config.mjs +120 -0
  394. package/src/generators/nextjs-app/files/hooks/use-toast.ts +7 -0
  395. package/src/generators/nextjs-app/files/instrumentation.ts +90 -0
  396. package/src/generators/nextjs-app/files/lib/api/fetcher.ts.template +130 -0
  397. package/src/generators/nextjs-app/files/lib/config.ts +21 -0
  398. package/src/generators/nextjs-app/files/lib/logger.ts +29 -0
  399. package/src/generators/nextjs-app/files/lib/schemas/index.ts +19 -0
  400. package/src/generators/nextjs-app/files/lib/utils.ts +6 -0
  401. package/src/generators/nextjs-app/files/next.config.mjs +9 -0
  402. package/src/generators/nextjs-app/files/package.json +70 -0
  403. package/src/generators/nextjs-app/files/postcss.config.mjs +8 -0
  404. package/src/generators/nextjs-app/files/proxy.test.ts.template +30 -0
  405. package/src/generators/nextjs-app/files/proxy.ts +31 -0
  406. package/src/generators/nextjs-app/files/public/.gitkeep +1 -0
  407. package/src/generators/nextjs-app/files/tsconfig.json +42 -0
  408. package/src/generators/nextjs-app/files/vitest.config.mts +15 -0
  409. package/src/generators/nextjs-app/files/vitest.setup.ts +7 -0
  410. package/src/generators/nextjs-app/generator.ts +307 -0
  411. package/src/generators/nextjs-app/schema.json +44 -0
  412. package/src/generators/python-microservice/docs/principles/stack/python/async.md +168 -0
  413. package/src/generators/python-microservice/docs/principles/stack/python/documentation.md +240 -0
  414. package/src/generators/python-microservice/docs/principles/stack/python/mcp.md +147 -0
  415. package/src/generators/python-microservice/docs/principles/stack/python/resilience.md +193 -0
  416. package/src/generators/python-microservice/docs/principles/stack/python/testing.md +281 -0
  417. package/src/generators/python-microservice/files/.env.example.template +30 -0
  418. package/src/generators/python-microservice/files/Dockerfile.template +36 -0
  419. package/src/generators/python-microservice/files/db/schema.sql.template +19 -0
  420. package/src/generators/python-microservice/files/pyproject.toml.template +76 -0
  421. package/src/generators/python-microservice/files/scripts/apply-schema.sh.template +25 -0
  422. package/src/generators/python-microservice/files/src/__packageName__/adapters/comfyui.py.template +87 -0
  423. package/src/generators/python-microservice/files/src/__packageName__/adapters/config.py.template +48 -0
  424. package/src/generators/python-microservice/files/src/__packageName__/adapters/database.py.template +21 -0
  425. package/src/generators/python-microservice/files/src/__packageName__/adapters/message_queue.py.template +29 -0
  426. package/src/generators/python-microservice/files/src/__packageName__/adapters/repository.py.template +130 -0
  427. package/src/generators/python-microservice/files/src/__packageName__/adapters/telemetry.py.template +68 -0
  428. package/src/generators/python-microservice/files/src/__packageName__/adapters/websocket_hub.py.template +36 -0
  429. package/src/generators/python-microservice/files/src/__packageName__/core/domain/entities.py.template +22 -0
  430. package/src/generators/python-microservice/files/src/__packageName__/core/domain/exceptions.py.template +43 -0
  431. package/src/generators/python-microservice/files/src/__packageName__/core/ports.py.template +42 -0
  432. package/src/generators/python-microservice/files/src/__packageName__/core/service/example_service.py.template +68 -0
  433. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/dependencies.py.template +50 -0
  434. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/middleware.py.template +131 -0
  435. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/router.py.template +37 -0
  436. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/websocket_handler.py.template +20 -0
  437. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/cleanup.py.template +35 -0
  438. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/worker.py.template +28 -0
  439. package/src/generators/python-microservice/files/src/__packageName__/main.py.template +108 -0
  440. package/src/generators/python-microservice/files/tests/test_main.py.template +74 -0
  441. package/src/generators/python-microservice/files/tests/test_middleware.py.template +109 -0
  442. package/src/generators/python-microservice/files/tests/test_worker.py.template +16 -0
  443. package/src/generators/python-microservice/generator.ts +286 -0
  444. package/src/generators/python-microservice/schema.json +86 -0
  445. package/src/generators/shared/brand-tokens.ts +301 -0
  446. package/src/generators/shared/capabilities.ts +349 -0
  447. package/src/generators/shared/provenance.ts +61 -0
  448. package/src/generators/shared/scaffold-helpers.ts +309 -0
  449. package/src/generators/system-test-runner/files/tests/bets/.gitkeep +0 -0
  450. package/src/generators/system-test-runner/files/tests/bets/_archive/.gitkeep +0 -0
  451. package/src/generators/system-test-runner/files/tests/conftest.py.template +503 -0
  452. package/src/generators/system-test-runner/files/tests/pyproject.toml.template +20 -0
  453. package/src/generators/system-test-runner/files/tests/system/pages/__init__.py.template +9 -0
  454. package/src/generators/system-test-runner/files/tests/system/pages/base_page.py.template +36 -0
  455. package/src/generators/system-test-runner/files/tests/system/test_a11y_smoke.py.template +132 -0
  456. package/src/generators/system-test-runner/files/tests/system/test_contract_conformance.py.template +140 -0
  457. package/src/generators/system-test-runner/files/tests/system/test_layout_geometry.py.template +109 -0
  458. package/src/generators/system-test-runner/files/tests/system/test_render_smoke.py.template +227 -0
  459. package/src/generators/system-test-runner/files/tests/system/test_system.py.template +158 -0
  460. package/src/generators/system-test-runner/files/tests/system/test_token_conformance.py.template +206 -0
  461. package/src/generators/system-test-runner/files/tests/system/test_visual_regression.py.template +104 -0
  462. package/src/generators/system-test-runner/generator.ts +142 -0
  463. package/src/generators/system-test-runner/schema.json +24 -0
  464. package/src/generators/workspace-dev-cli/cli-src/build.mjs +42 -0
  465. package/src/generators/workspace-dev-cli/cli-src/dist/dev-bundle.js +2168 -0
  466. package/src/generators/workspace-dev-cli/cli-src/src/commands/bet.ts +442 -0
  467. package/src/generators/workspace-dev-cli/cli-src/src/commands/completion.ts +87 -0
  468. package/src/generators/workspace-dev-cli/cli-src/src/commands/doctor.ts +139 -0
  469. package/src/generators/workspace-dev-cli/cli-src/src/commands/lifecycle.ts +548 -0
  470. package/src/generators/workspace-dev-cli/cli-src/src/commands/quality.ts +127 -0
  471. package/src/generators/workspace-dev-cli/cli-src/src/commands/surface.ts +214 -0
  472. package/src/generators/workspace-dev-cli/cli-src/src/index.ts +127 -0
  473. package/src/generators/workspace-dev-cli/cli-src/src/registry.ts +194 -0
  474. package/src/generators/workspace-dev-cli/cli-src/src/theme/color.ts +130 -0
  475. package/src/generators/workspace-dev-cli/cli-src/src/theme/render.ts +158 -0
  476. package/src/generators/workspace-dev-cli/cli-src/src/theme/tokens.ts +122 -0
  477. package/src/generators/workspace-dev-cli/cli-src/src/util/context.ts +43 -0
  478. package/src/generators/workspace-dev-cli/cli-src/src/util/extensions.ts +99 -0
  479. package/src/generators/workspace-dev-cli/cli-src/src/util/paths.ts +46 -0
  480. package/src/generators/workspace-dev-cli/cli-src/src/util/proc.ts +106 -0
  481. package/src/generators/workspace-dev-cli/cli-src/src/util/prompt.ts +108 -0
  482. package/src/generators/workspace-dev-cli/cli-src/src/util/runners.ts +70 -0
  483. package/src/generators/workspace-dev-cli/cli-src/src/util/services.ts +221 -0
  484. package/src/generators/workspace-dev-cli/cli-src/src/util/version.ts +21 -0
  485. package/src/generators/workspace-dev-cli/cli-src/tsconfig.json +16 -0
  486. package/src/generators/workspace-dev-cli/files/.agents/skills/workspace-cli/SKILL.md.template +74 -0
  487. package/src/generators/workspace-dev-cli/files/dev.template +16 -0
  488. package/src/generators/workspace-dev-cli/files/docker-compose.yml.template +20 -0
  489. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/milestone-test.pytmpl.template +46 -0
  490. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/slice-test.pytmpl.template +38 -0
  491. package/src/generators/workspace-dev-cli/generator.ts +136 -0
  492. package/src/generators/workspace-dev-cli/schema.json +22 -0
  493. package/src/hidden-skills/code-intelligence.md +129 -0
  494. package/src/hidden-skills/groundwork-architect/SKILL.md +114 -0
  495. package/src/hidden-skills/groundwork-architect/references/agentic-systems.md +44 -0
  496. package/src/hidden-skills/groundwork-architect/references/ai-native-architecture.md +37 -0
  497. package/src/hidden-skills/groundwork-architect/references/api-and-contracts.md +45 -0
  498. package/src/hidden-skills/groundwork-architect/references/core-and-boundaries.md +45 -0
  499. package/src/hidden-skills/groundwork-architect/references/data-architecture.md +33 -0
  500. package/src/hidden-skills/groundwork-architect/references/decision-records.md +34 -0
  501. package/src/hidden-skills/groundwork-architect/references/durable-execution.md +45 -0
  502. package/src/hidden-skills/groundwork-architect/references/evolutionary-architecture.md +37 -0
  503. package/src/hidden-skills/groundwork-architect/references/identity-and-access.md +41 -0
  504. package/src/hidden-skills/groundwork-architect/references/integration-patterns.md +39 -0
  505. package/src/hidden-skills/groundwork-architect/references/observability.md +36 -0
  506. package/src/hidden-skills/groundwork-architect/references/performance-and-scale.md +41 -0
  507. package/src/hidden-skills/groundwork-architect/references/platform-and-delivery.md +47 -0
  508. package/src/hidden-skills/groundwork-architect/references/realtime-and-async.md +28 -0
  509. package/src/hidden-skills/groundwork-architect/references/reliability.md +31 -0
  510. package/src/hidden-skills/groundwork-architect/references/security-and-trust.md +47 -0
  511. package/src/hidden-skills/groundwork-architect/references/surface-architecture.md +40 -0
  512. package/src/hidden-skills/groundwork-architect/sync-anchor.md +34 -0
  513. package/src/hidden-skills/groundwork-architecture/architecture-template.md +50 -0
  514. package/src/hidden-skills/groundwork-architecture/instructions.md +139 -0
  515. package/src/hidden-skills/groundwork-architecture/phases/01-context-ingestion.md +18 -0
  516. package/src/hidden-skills/groundwork-architecture/phases/02-technical-constraints.md +27 -0
  517. package/src/hidden-skills/groundwork-architecture/phases/03-service-design.md +19 -0
  518. package/src/hidden-skills/groundwork-architecture/phases/04-data-flow-communication.md +23 -0
  519. package/src/hidden-skills/groundwork-architecture/phases/05-component-boundaries-contracts.md +17 -0
  520. package/src/hidden-skills/groundwork-architecture/phases/06-draft-review-present.md +38 -0
  521. package/src/hidden-skills/groundwork-architecture/phases/07-commit.md +33 -0
  522. package/src/hidden-skills/groundwork-architecture/templates/architecture-cache.md +43 -0
  523. package/src/hidden-skills/groundwork-architecture-extract/instructions.md +163 -0
  524. package/src/hidden-skills/groundwork-architecture-extract/templates/architecture-extract-cache.md +21 -0
  525. package/src/hidden-skills/groundwork-bet/briefs/slice-worker.md +191 -0
  526. package/src/hidden-skills/groundwork-bet/instructions.md +88 -0
  527. package/src/hidden-skills/groundwork-bet/templates/bet-progress-test.md +126 -0
  528. package/src/hidden-skills/groundwork-bet/templates/change-proposal.md +38 -0
  529. package/src/hidden-skills/groundwork-bet/templates/decomposition/meta.json +4 -0
  530. package/src/hidden-skills/groundwork-bet/templates/decomposition/milestone-index.md +35 -0
  531. package/src/hidden-skills/groundwork-bet/templates/decomposition/slice.md +35 -0
  532. package/src/hidden-skills/groundwork-bet/templates/pitch.md +45 -0
  533. package/src/hidden-skills/groundwork-bet/templates/technical-design/01-ui-design.md +51 -0
  534. package/src/hidden-skills/groundwork-bet/templates/technical-design/02-data-flows.md +36 -0
  535. package/src/hidden-skills/groundwork-bet/templates/technical-design/03-api-design.md +90 -0
  536. package/src/hidden-skills/groundwork-bet/templates/technical-design/04-data-design.md +29 -0
  537. package/src/hidden-skills/groundwork-bet/workflows/01-discovery.md +198 -0
  538. package/src/hidden-skills/groundwork-bet/workflows/02-design.md +168 -0
  539. package/src/hidden-skills/groundwork-bet/workflows/03-decomposition.md +246 -0
  540. package/src/hidden-skills/groundwork-bet/workflows/04-delivery.md +193 -0
  541. package/src/hidden-skills/groundwork-bet/workflows/05-validation.md +199 -0
  542. package/src/hidden-skills/groundwork-design-system/instructions.md +125 -0
  543. package/src/hidden-skills/groundwork-design-system/templates/brand-tokens.md +182 -0
  544. package/src/hidden-skills/groundwork-design-system/templates/design-system-cache.md +64 -0
  545. package/src/hidden-skills/groundwork-design-system/tracks/_foundation.md +136 -0
  546. package/src/hidden-skills/groundwork-design-system/tracks/agentic-protocol.md +269 -0
  547. package/src/hidden-skills/groundwork-design-system/tracks/cli.md +355 -0
  548. package/src/hidden-skills/groundwork-design-system/tracks/graphical-ui.md +330 -0
  549. package/src/hidden-skills/groundwork-design-system-extract/instructions.md +124 -0
  550. package/src/hidden-skills/groundwork-design-system-extract/templates/design-system-extract-cache.md +19 -0
  551. package/src/hidden-skills/groundwork-designer/SKILL.md +108 -0
  552. package/src/hidden-skills/groundwork-designer/references/accessibility.md +33 -0
  553. package/src/hidden-skills/groundwork-designer/references/ai-native-design.md +37 -0
  554. package/src/hidden-skills/groundwork-designer/references/design-review.md +29 -0
  555. package/src/hidden-skills/groundwork-designer/references/design-systems-and-tokens.md +33 -0
  556. package/src/hidden-skills/groundwork-designer/references/interaction-and-motion.md +37 -0
  557. package/src/hidden-skills/groundwork-designer/references/layout-and-space.md +33 -0
  558. package/src/hidden-skills/groundwork-designer/references/usability-and-ux.md +33 -0
  559. package/src/hidden-skills/groundwork-designer/references/visual-craft.md +49 -0
  560. package/src/hidden-skills/groundwork-designer/sync-anchor.md +20 -0
  561. package/src/hidden-skills/groundwork-doc-sync/instructions.md +100 -0
  562. package/src/hidden-skills/groundwork-elicit/instructions.md +66 -0
  563. package/src/hidden-skills/groundwork-elicit/methods.md +65 -0
  564. package/src/hidden-skills/groundwork-infra-adopt/instructions.md +168 -0
  565. package/src/hidden-skills/groundwork-infra-adopt/templates/infra-adopt-cache.md +21 -0
  566. package/src/hidden-skills/groundwork-mvp/instructions.md +223 -0
  567. package/src/hidden-skills/groundwork-mvp/templates/mvp-cache.md +9 -0
  568. package/src/hidden-skills/groundwork-patch/instructions.md +40 -0
  569. package/src/hidden-skills/groundwork-persona/instructions.md +54 -0
  570. package/src/hidden-skills/groundwork-product/SKILL.md +102 -0
  571. package/src/hidden-skills/groundwork-product/references/ai-native-product.md +45 -0
  572. package/src/hidden-skills/groundwork-product/references/discovery-and-opportunity.md +38 -0
  573. package/src/hidden-skills/groundwork-product/references/product-risks.md +52 -0
  574. package/src/hidden-skills/groundwork-product/references/requirements-and-specs.md +39 -0
  575. package/src/hidden-skills/groundwork-product/references/scope-and-sequencing.md +35 -0
  576. package/src/hidden-skills/groundwork-product/references/shaping-and-appetite.md +48 -0
  577. package/src/hidden-skills/groundwork-product/references/success-metrics-and-signals.md +37 -0
  578. package/src/hidden-skills/groundwork-product/sync-anchor.md +19 -0
  579. package/src/hidden-skills/groundwork-product-brief/instructions.md +231 -0
  580. package/src/hidden-skills/groundwork-product-brief-extract/instructions.md +139 -0
  581. package/src/hidden-skills/groundwork-product-brief-extract/templates/product-brief-extract-cache.md +17 -0
  582. package/src/hidden-skills/groundwork-review/checklists/architecture.md +93 -0
  583. package/src/hidden-skills/groundwork-review/checklists/bet-pitch.md +94 -0
  584. package/src/hidden-skills/groundwork-review/checklists/decomposition.md +135 -0
  585. package/src/hidden-skills/groundwork-review/checklists/design-system.md +85 -0
  586. package/src/hidden-skills/groundwork-review/checklists/domain-entity.md +66 -0
  587. package/src/hidden-skills/groundwork-review/checklists/implementation-readiness.md +46 -0
  588. package/src/hidden-skills/groundwork-review/checklists/infrastructure.md +68 -0
  589. package/src/hidden-skills/groundwork-review/checklists/maturity.md +71 -0
  590. package/src/hidden-skills/groundwork-review/checklists/product-brief.md +69 -0
  591. package/src/hidden-skills/groundwork-review/checklists/technical-design.md +112 -0
  592. package/src/hidden-skills/groundwork-review/instructions.md +181 -0
  593. package/src/hidden-skills/groundwork-scaffold/instructions.md +254 -0
  594. package/src/hidden-skills/groundwork-scaffold/phases/01-ingestion-service-mapping.md +87 -0
  595. package/src/hidden-skills/groundwork-scaffold/phases/02-scaffolding-execution.md +15 -0
  596. package/src/hidden-skills/groundwork-scaffold/phases/03-service-documentation-api-stubs.md +100 -0
  597. package/src/hidden-skills/groundwork-scaffold/phases/04-infrastructure-verification.md +17 -0
  598. package/src/hidden-skills/groundwork-scaffold/phases/05-draft-review.md +19 -0
  599. package/src/hidden-skills/groundwork-scaffold/phases/06-commit.md +19 -0
  600. package/src/hidden-skills/groundwork-scaffold/templates/scaffold-cache.md +23 -0
  601. package/src/hidden-skills/groundwork-scan/instructions.md +164 -0
  602. package/src/hidden-skills/groundwork-scan/references/digest-schema.md +66 -0
  603. package/src/hidden-skills/groundwork-scan/references/exclusions.md +44 -0
  604. package/src/hidden-skills/groundwork-scan/templates/architecture-findings.md +42 -0
  605. package/src/hidden-skills/groundwork-scan/templates/design-findings.md +23 -0
  606. package/src/hidden-skills/groundwork-scan/templates/overview.md +26 -0
  607. package/src/hidden-skills/groundwork-scan/templates/product-findings.md +23 -0
  608. package/src/hidden-skills/groundwork-scan/templates/scan-state.json +19 -0
  609. package/src/hidden-skills/groundwork-stack-forge/instructions.md +150 -0
  610. package/src/hidden-skills/groundwork-stack-forge/references/authoring-engineer-skills.md +107 -0
  611. package/src/hidden-skills/groundwork-surface-activation/instructions.md +138 -0
  612. package/src/hidden-skills/groundwork-update/briefs/reconcile-worker.md +196 -0
  613. package/src/hidden-skills/groundwork-update/instructions.md +200 -0
  614. package/src/hidden-skills/groundwork-writer/SKILL.md +278 -0
  615. package/src/hidden-skills/maturity-model.md +125 -0
  616. package/src/hidden-skills/operating-contract.md +400 -0
  617. package/src/hidden-skills/repo-map-schema.md +90 -0
  618. package/src/hidden-skills/templates/adr.md +57 -0
  619. package/src/hidden-skills/templates/capability-ports.md +71 -0
  620. package/src/hidden-skills/templates/discovery-notes.md +33 -0
  621. package/src/hidden-skills/templates/domain-entity.md +80 -0
  622. package/src/hidden-skills/templates/gap-ledger.md +21 -0
  623. package/src/hidden-skills/templates/handoff.md +37 -0
  624. package/src/hidden-skills/templates/maturity.md +39 -0
  625. package/src/hidden-skills/templates/surfaces.md +207 -0
  626. package/src/skills/groundwork-check/SKILL.md +56 -0
  627. package/src/skills/groundwork-check/instructions.md +70 -0
  628. package/src/skills/groundwork-orchestrator/SKILL.md +176 -0
  629. package/src/skills/groundwork-orchestrator/workflow-index.md +50 -0
@@ -0,0 +1,130 @@
1
+ import base64
2
+ import json
3
+ import datetime
4
+ from typing import Optional, Tuple
5
+ from sqlalchemy.ext.asyncio import AsyncSession
6
+ from sqlalchemy import select, func
7
+ from sqlalchemy.dialects.postgresql import insert
8
+ from sqlalchemy.orm import Mapped, mapped_column
9
+ from <%= packageName %>.core.domain.entities import ExampleEntity, PaginatedResult, IdempotencyResponse
10
+ from <%= packageName %>.adapters.database import Base
11
+
12
+ # SQLAlchemy Models
13
+ class ExampleModel(Base):
14
+ __tablename__ = "examples"
15
+
16
+ id: Mapped[str] = mapped_column(primary_key=True)
17
+ name: Mapped[str]
18
+ description: Mapped[Optional[str]]
19
+
20
+ def to_domain(self) -> ExampleEntity:
21
+ return ExampleEntity(id=self.id, name=self.name, description=self.description)
22
+
23
+ @classmethod
24
+ def from_domain(cls, entity: ExampleEntity) -> "ExampleModel":
25
+ return cls(id=entity.id, name=entity.name, description=entity.description)
26
+
27
+ class IdempotencyKeyModel(Base):
28
+ __tablename__ = "idempotency_keys"
29
+
30
+ key: Mapped[str] = mapped_column(primary_key=True)
31
+ user_id: Mapped[str]
32
+ status: Mapped[str]
33
+ response_code: Mapped[Optional[int]]
34
+ response_body: Mapped[Optional[str]]
35
+ response_headers: Mapped[Optional[str]]
36
+ created_at: Mapped[datetime.datetime] = mapped_column(server_default=func.now())
37
+ updated_at: Mapped[datetime.datetime] = mapped_column(server_default=func.now(), onupdate=func.now())
38
+
39
+ # Repository Implementation
40
+ class PostgresExampleRepository:
41
+ def __init__(self, session: AsyncSession):
42
+ self.session = session
43
+
44
+ async def get_by_id(self, entity_id: str) -> Optional[ExampleEntity]:
45
+ result = await self.session.execute(
46
+ select(ExampleModel).where(ExampleModel.id == entity_id)
47
+ )
48
+ model = result.scalar_one_or_none()
49
+ return model.to_domain() if model else None
50
+
51
+ async def save(self, entity: ExampleEntity) -> None:
52
+ model = ExampleModel.from_domain(entity)
53
+ self.session.add(model)
54
+ await self.session.commit()
55
+
56
+ async def list_items(self, limit: int = 10, cursor: Optional[str] = None) -> PaginatedResult[ExampleEntity]:
57
+ query = select(ExampleModel).order_by(ExampleModel.id.asc()).limit(limit + 1)
58
+
59
+ if cursor:
60
+ try:
61
+ decoded_cursor = base64.b64decode(cursor).decode('utf-8')
62
+ query = query.where(ExampleModel.id > decoded_cursor)
63
+ except Exception:
64
+ pass # Invalid cursor handled gracefully
65
+
66
+ result = await self.session.execute(query)
67
+ models = result.scalars().all()
68
+
69
+ has_more = len(models) > limit
70
+ items = models[:limit]
71
+
72
+ next_cursor = None
73
+ if has_more and items:
74
+ last_id = items[-1].id
75
+ next_cursor = base64.b64encode(last_id.encode('utf-8')).decode('utf-8')
76
+
77
+ domain_items = [model.to_domain() for model in items]
78
+ return PaginatedResult(items=domain_items, next_cursor=next_cursor, has_more=has_more)
79
+
80
+ class PostgresIdempotencyRepository:
81
+ def __init__(self, session: AsyncSession):
82
+ self.session = session
83
+
84
+ async def get(self, key: str, user_id: str) -> Optional[Tuple[str, Optional[IdempotencyResponse]]]:
85
+ result = await self.session.execute(
86
+ select(IdempotencyKeyModel).where(
87
+ IdempotencyKeyModel.key == key,
88
+ IdempotencyKeyModel.user_id == user_id
89
+ )
90
+ )
91
+ model = result.scalar_one_or_none()
92
+ if not model:
93
+ return None
94
+
95
+ if model.status == "COMPLETED" and model.response_code is not None:
96
+ headers = json.loads(model.response_headers) if model.response_headers else {}
97
+ resp = IdempotencyResponse(
98
+ status_code=model.response_code,
99
+ headers=headers,
100
+ body=model.response_body or ""
101
+ )
102
+ return (model.status, resp)
103
+
104
+ return (model.status, None)
105
+
106
+ async def lock(self, key: str, user_id: str) -> bool:
107
+ # Atomic insert: if the key exists, do nothing (fails to acquire lock)
108
+ stmt = insert(IdempotencyKeyModel).values(
109
+ key=key,
110
+ user_id=user_id,
111
+ status="IN_PROGRESS"
112
+ ).on_conflict_do_nothing()
113
+
114
+ result = await self.session.execute(stmt)
115
+ await self.session.commit()
116
+ return result.rowcount > 0
117
+
118
+ async def save(self, key: str, user_id: str, response: IdempotencyResponse) -> None:
119
+ result = await self.session.execute(
120
+ select(IdempotencyKeyModel).where(
121
+ IdempotencyKeyModel.key == key,
122
+ IdempotencyKeyModel.user_id == user_id
123
+ )
124
+ )
125
+ model = result.scalar_one()
126
+ model.status = "COMPLETED"
127
+ model.response_code = response.status_code
128
+ model.response_body = response.body
129
+ model.response_headers = json.dumps(response.headers)
130
+ await self.session.commit()
@@ -0,0 +1,68 @@
1
+ """OpenTelemetry bootstrap for the FastAPI app.
2
+
3
+ Builds a TracerProvider with an OTLP gRPC exporter and instruments the FastAPI
4
+ app so inbound requests produce spans that are exported to the configured
5
+ collector (Jaeger in dev). Mirrors the Go scaffold: BatchSpanProcessor +
6
+ ParentBased(AlwaysSample) default sampler, service.name set on the resource.
7
+
8
+ Also configures structured JSON logging with trace_id/span_id correlation so
9
+ logs are joinable to traces.
10
+ """
11
+ import logging
12
+
13
+ from opentelemetry import trace
14
+ from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
15
+ from opentelemetry.instrumentation.fastapi import FastAPIInstrumentor
16
+ from opentelemetry.sdk.resources import Resource
17
+ from opentelemetry.sdk.trace import TracerProvider
18
+ from opentelemetry.sdk.trace.export import BatchSpanProcessor
19
+ from opentelemetry.semconv.resource import ResourceAttributes
20
+ from pythonjsonlogger import jsonlogger
21
+
22
+
23
+ def setup_telemetry(app, endpoint: str) -> TracerProvider:
24
+ """Initialize tracing and instrument the FastAPI app.
25
+
26
+ Returns the TracerProvider so the caller can shut it down (flush the
27
+ BatchSpanProcessor) on application stop.
28
+ """
29
+ resource = Resource.create({ResourceAttributes.SERVICE_NAME: "<%= name %>"})
30
+
31
+ provider = TracerProvider(resource=resource)
32
+ # insecure=True: the dev endpoint is plain h2c (http://...:4317), no TLS.
33
+ exporter = OTLPSpanExporter(endpoint=endpoint, insecure=True)
34
+ provider.add_span_processor(BatchSpanProcessor(exporter))
35
+
36
+ trace.set_tracer_provider(provider)
37
+ FastAPIInstrumentor.instrument_app(app)
38
+ return provider
39
+
40
+
41
+ class _TraceContextFilter(logging.Filter):
42
+ """Attaches the active span's trace_id/span_id to every log record."""
43
+
44
+ def filter(self, record: logging.LogRecord) -> bool:
45
+ span = trace.get_current_span()
46
+ ctx = span.get_span_context()
47
+ if ctx.is_valid:
48
+ record.trace_id = format(ctx.trace_id, "032x")
49
+ record.span_id = format(ctx.span_id, "016x")
50
+ else:
51
+ record.trace_id = ""
52
+ record.span_id = ""
53
+ return True
54
+
55
+
56
+ def setup_logging() -> None:
57
+ """Configure root logging as JSON with trace correlation fields."""
58
+ handler = logging.StreamHandler()
59
+ handler.setFormatter(
60
+ jsonlogger.JsonFormatter(
61
+ "%(asctime)s %(levelname)s %(name)s %(message)s %(trace_id)s %(span_id)s"
62
+ )
63
+ )
64
+ handler.addFilter(_TraceContextFilter())
65
+ root = logging.getLogger()
66
+ root.handlers.clear()
67
+ root.addHandler(handler)
68
+ root.setLevel(logging.INFO)
@@ -0,0 +1,36 @@
1
+ import json
2
+ import redis.asyncio as redis
3
+ from <%= packageName %>.adapters.config import settings
4
+ import asyncio
5
+ from typing import Set
6
+
7
+ class WebSocketHub:
8
+ def __init__(self):
9
+ self.redis = redis.from_url(settings.redis_url)
10
+ self.pubsub = self.redis.pubsub()
11
+ self.active_connections: Set = set()
12
+ self.background_tasks: Set[asyncio.Task] = set()
13
+
14
+ async def connect(self, websocket):
15
+ await websocket.accept()
16
+ self.active_connections.add(websocket)
17
+
18
+ def disconnect(self, websocket):
19
+ self.active_connections.discard(websocket)
20
+
21
+ async def subscribe(self, channel: str):
22
+ await self.pubsub.subscribe(channel)
23
+
24
+ task = asyncio.create_task(self._listen())
25
+ self.background_tasks.add(task)
26
+ task.add_done_callback(self.background_tasks.discard)
27
+
28
+ async def _listen(self):
29
+ async for message in self.pubsub.listen():
30
+ if message['type'] == 'message':
31
+ data = message['data'].decode('utf-8')
32
+ for connection in self.active_connections:
33
+ await connection.send_text(data)
34
+
35
+ async def broadcast(self, channel: str, message: dict):
36
+ await self.redis.publish(channel, json.dumps(message))
@@ -0,0 +1,22 @@
1
+ from typing import Generic, TypeVar, List, Optional, Dict, Any
2
+ from pydantic import BaseModel, Field
3
+
4
+ T = TypeVar("T")
5
+
6
+ class PaginatedResult(BaseModel, Generic[T]):
7
+ """Generic cursor-based pagination result."""
8
+ items: List[T]
9
+ next_cursor: Optional[str] = None
10
+ has_more: bool = False
11
+
12
+ class IdempotencyResponse(BaseModel):
13
+ """Domain representation of a cached HTTP response."""
14
+ status_code: int
15
+ headers: Dict[str, str]
16
+ body: str
17
+
18
+ class ExampleEntity(BaseModel):
19
+ """An example entity for the service."""
20
+ id: str
21
+ name: str
22
+ description: Optional[str] = None
@@ -0,0 +1,43 @@
1
+ class DomainError(Exception):
2
+ """Base class for domain exceptions."""
3
+ pass
4
+
5
+ class NotFoundError(DomainError):
6
+ """Raised when a requested resource is not found."""
7
+ pass
8
+
9
+ class UnauthorizedError(DomainError):
10
+ """Raised when authentication is missing or invalid."""
11
+ pass
12
+
13
+ class ForbiddenError(DomainError):
14
+ """Raised when the user does not have permission."""
15
+ pass
16
+
17
+ class ConflictError(DomainError):
18
+ """Raised when there is a conflict, such as a duplicate resource."""
19
+ pass
20
+
21
+ class ValidationError(DomainError):
22
+ """Raised for field-level validation errors."""
23
+ pass
24
+
25
+ class IdempotencyError(DomainError):
26
+ """Raised when an idempotency key collision occurs."""
27
+ pass
28
+
29
+ class RateLimitExceededError(DomainError):
30
+ """Raised when concurrency limits or rate limits are exceeded."""
31
+ pass
32
+
33
+ class CircuitBreakerOpenError(DomainError):
34
+ """Raised when an external service circuit breaker is open."""
35
+ pass
36
+
37
+ class TransientInferenceError(DomainError):
38
+ """Raised for retriable provider/ML failures."""
39
+ pass
40
+
41
+ class PermanentInferenceError(DomainError):
42
+ """Raised for non-retriable provider/ML failures."""
43
+ pass
@@ -0,0 +1,42 @@
1
+ from typing import Protocol, Optional, Tuple
2
+ from <%= packageName %>.core.domain.entities import ExampleEntity, PaginatedResult, IdempotencyResponse
3
+
4
+ class IdempotencyRepository(Protocol):
5
+ """Port for storing idempotency state."""
6
+
7
+ async def get(self, key: str, user_id: str) -> Optional[Tuple[str, Optional[IdempotencyResponse]]]:
8
+ """Returns (status, cached_response) if key exists, else None."""
9
+ ...
10
+
11
+ async def lock(self, key: str, user_id: str) -> bool:
12
+ """Attempts to acquire lock (IN_PROGRESS). Returns True if successful."""
13
+ ...
14
+
15
+ async def save(self, key: str, user_id: str, response: IdempotencyResponse) -> None:
16
+ """Saves completed response and marks as COMPLETED."""
17
+ ...
18
+
19
+ <% if (postgres) { %>
20
+ class ExampleRepository(Protocol):
21
+ """Port for ExampleEntity storage."""
22
+
23
+ async def get_by_id(self, entity_id: str) -> Optional[ExampleEntity]:
24
+ ...
25
+
26
+ async def save(self, entity: ExampleEntity) -> None:
27
+ ...
28
+
29
+ async def list_items(self, limit: int = 10, cursor: Optional[str] = None) -> PaginatedResult[ExampleEntity]:
30
+ ...
31
+ <% } %>
32
+
33
+ <% if (messaging !== 'none') { %>
34
+ class MessageQueue(Protocol):
35
+ """Port for publishing events."""
36
+
37
+ async def publish(self, topic: str, payload: dict) -> None:
38
+ ...
39
+ <% } %>
40
+ <%# The TextGenerator port lives in the package's core/llm.py, generated by the
41
+ llm capability (plan WS-F), so the same port is reusable by the standalone
42
+ add-capability generator on existing services. %>
@@ -0,0 +1,68 @@
1
+ from <%= packageName %>.core.domain.entities import ExampleEntity, PaginatedResult
2
+ from <%= packageName %>.core.domain.exceptions import NotFoundError
3
+ <% if (postgres) { %>
4
+ from <%= packageName %>.core.ports import ExampleRepository
5
+ <% } %>
6
+ <% if (messaging !== 'none') { %>
7
+ from <%= packageName %>.core.ports import MessageQueue
8
+ <% } %>
9
+ <% if (llm) { %>
10
+ from <%= packageName %>.core.llm import TextGenerator
11
+ <% } %>
12
+ import uuid
13
+
14
+ class ExampleService:
15
+ def __init__(
16
+ self,
17
+ <% if (postgres) { %>
18
+ repository: ExampleRepository,
19
+ <% } %>
20
+ <% if (messaging !== 'none') { %>
21
+ message_queue: MessageQueue,
22
+ <% } %>
23
+ <% if (llm) { %>
24
+ text_generator: TextGenerator,
25
+ <% } %>
26
+ ):
27
+ <% if (postgres) { %>
28
+ self.repository = repository
29
+ <% } %>
30
+ <% if (messaging !== 'none') { %>
31
+ self.message_queue = message_queue
32
+ <% } %>
33
+ <% if (llm) { %>
34
+ self.text_generator = text_generator
35
+ <% } %>
36
+ <% if (!postgres && messaging === 'none' && !llm) { %>
37
+ pass
38
+ <% } %>
39
+
40
+ async def create_example(self, name: str) -> ExampleEntity:
41
+ entity = ExampleEntity(id=str(uuid.uuid4()), name=name)
42
+
43
+ <% if (llm) { %>
44
+ # Generate description using LLM
45
+ description = await self.text_generator.generate_text(f"Describe a thing named {name}")
46
+ entity.description = description
47
+ <% } %>
48
+
49
+ <% if (postgres) { %>
50
+ await self.repository.save(entity)
51
+ <% } %>
52
+
53
+ <% if (messaging !== 'none') { %>
54
+ await self.message_queue.publish("example.created", entity.model_dump())
55
+ <% } %>
56
+
57
+ return entity
58
+
59
+ <% if (postgres) { %>
60
+ async def get_example(self, entity_id: str) -> ExampleEntity:
61
+ entity = await self.repository.get_by_id(entity_id)
62
+ if not entity:
63
+ raise NotFoundError(f"Example {entity_id} not found")
64
+ return entity
65
+
66
+ async def list_examples(self, limit: int = 10, cursor: str | None = None) -> PaginatedResult[ExampleEntity]:
67
+ return await self.repository.list_items(limit, cursor)
68
+ <% } %>
@@ -0,0 +1,50 @@
1
+ from fastapi import Depends
2
+ from <%= packageName %>.core.service.example_service import ExampleService
3
+
4
+ <% if (postgres) { %>
5
+ from sqlalchemy.ext.asyncio import AsyncSession
6
+ from <%= packageName %>.core.ports import ExampleRepository
7
+ from <%= packageName %>.adapters.database import get_db_session
8
+ from <%= packageName %>.adapters.repository import PostgresExampleRepository
9
+
10
+ def get_example_repository(session: AsyncSession = Depends(get_db_session)) -> ExampleRepository:
11
+ return PostgresExampleRepository(session)
12
+ <% } %>
13
+
14
+ <% if (messaging !== 'none') { %>
15
+ from <%= packageName %>.core.ports import MessageQueue
16
+ from <%= packageName %>.adapters.message_queue import <% if (messaging === 'redis') { %>RedisMessageQueue<% } else if (messaging === 'kafka') { %>KafkaMessageQueue<% } else { %>GCPMessageQueue<% } %>
17
+ def get_message_queue() -> MessageQueue:
18
+ # In a real app this might be a singleton in app state, but for scaffold we instantiate
19
+ return <% if (messaging === 'redis') { %>RedisMessageQueue()<% } else if (messaging === 'kafka') { %>KafkaMessageQueue()<% } else { %>GCPMessageQueue()<% } %>
20
+ <% } %>
21
+
22
+ <% if (llm) { %>
23
+ from <%= packageName %>.core.llm import TextGenerator
24
+ from <%= packageName %>.adapters.llm import LLMClient
25
+ def get_text_generator() -> TextGenerator:
26
+ return LLMClient()
27
+ <% } %>
28
+
29
+ def get_example_service(
30
+ <% if (postgres) { %>
31
+ repository: ExampleRepository = Depends(get_example_repository),
32
+ <% } %>
33
+ <% if (messaging !== 'none') { %>
34
+ message_queue: MessageQueue = Depends(get_message_queue),
35
+ <% } %>
36
+ <% if (llm) { %>
37
+ text_generator: TextGenerator = Depends(get_text_generator),
38
+ <% } %>
39
+ ) -> ExampleService:
40
+ return ExampleService(
41
+ <% if (postgres) { %>
42
+ repository=repository,
43
+ <% } %>
44
+ <% if (messaging !== 'none') { %>
45
+ message_queue=message_queue,
46
+ <% } %>
47
+ <% if (llm) { %>
48
+ text_generator=text_generator,
49
+ <% } %>
50
+ )
@@ -0,0 +1,131 @@
1
+ import json
2
+ import asyncio
3
+ from typing import Optional
4
+ from fastapi import Request, status
5
+ from fastapi.responses import JSONResponse
6
+ from starlette.middleware.base import BaseHTTPMiddleware
7
+ from <%= packageName %>.core.domain.exceptions import (
8
+ NotFoundError,
9
+ ConflictError,
10
+ ValidationError,
11
+ IdempotencyError,
12
+ RateLimitExceededError,
13
+ CircuitBreakerOpenError,
14
+ TransientInferenceError
15
+ )
16
+ from <%= packageName %>.core.ports import IdempotencyRepository
17
+ from <%= packageName %>.core.domain.entities import IdempotencyResponse
18
+ from <%= packageName %>.adapters.config import settings
19
+
20
+ class DomainExceptionHandlerMiddleware(BaseHTTPMiddleware):
21
+ """Maps domain exceptions to appropriate HTTP responses."""
22
+ async def dispatch(self, request: Request, call_next):
23
+ try:
24
+ return await call_next(request)
25
+ except NotFoundError as e:
26
+ return JSONResponse(status_code=status.HTTP_404_NOT_FOUND, content={"detail": str(e)})
27
+ except (ConflictError, IdempotencyError) as e:
28
+ return JSONResponse(status_code=status.HTTP_409_CONFLICT, content={"detail": str(e)})
29
+ except ValidationError as e:
30
+ return JSONResponse(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, content={"detail": str(e)})
31
+ except RateLimitExceededError as e:
32
+ return JSONResponse(status_code=status.HTTP_429_TOO_MANY_REQUESTS, content={"detail": str(e)})
33
+ except (TransientInferenceError, CircuitBreakerOpenError) as e:
34
+ return JSONResponse(status_code=status.HTTP_503_SERVICE_UNAVAILABLE, content={"detail": str(e)})
35
+ except Exception as e:
36
+ # Let unhandled exceptions propagate or log them here
37
+ raise e
38
+
39
+ class GlobalTimeoutMiddleware(BaseHTTPMiddleware):
40
+ """Ensures requests do not hang indefinitely."""
41
+ def __init__(self, app, timeout: float = 30.0):
42
+ super().__init__(app)
43
+ self.timeout = timeout
44
+
45
+ async def dispatch(self, request: Request, call_next):
46
+ try:
47
+ return await asyncio.wait_for(call_next(request), timeout=self.timeout)
48
+ except asyncio.TimeoutError:
49
+ return JSONResponse(
50
+ status_code=status.HTTP_504_GATEWAY_TIMEOUT,
51
+ content={"detail": "Request execution timed out."}
52
+ )
53
+
54
+ class ConcurrencyLimitingMiddleware(BaseHTTPMiddleware):
55
+ """Load shedder utilizing a semaphore to limit concurrent requests."""
56
+ def __init__(self, app, max_concurrent_requests: int):
57
+ super().__init__(app)
58
+ self.semaphore = asyncio.Semaphore(max_concurrent_requests)
59
+
60
+ async def dispatch(self, request: Request, call_next):
61
+ if self.semaphore.locked():
62
+ return JSONResponse(
63
+ status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
64
+ content={"detail": "Service overloaded. Please try again later."}
65
+ )
66
+ async with self.semaphore:
67
+ return await call_next(request)
68
+
69
+ class IdempotencyMiddleware(BaseHTTPMiddleware):
70
+ """
71
+ Ensures mutating requests (POST/PUT/PATCH/DELETE) with an Idempotency-Key
72
+ are only executed once. Uses injected IdempotencyRepository from app state.
73
+ """
74
+ async def dispatch(self, request: Request, call_next):
75
+ if request.method in ["GET", "OPTIONS", "HEAD"]:
76
+ return await call_next(request)
77
+
78
+ idem_key = request.headers.get("Idempotency-Key")
79
+ if not idem_key:
80
+ return await call_next(request)
81
+
82
+ # In real life, extract user_id from auth token
83
+ user_id = "anonymous"
84
+
85
+ # We need the repository. Ideally injected into app state during lifespan.
86
+ repo: Optional[IdempotencyRepository] = getattr(request.app.state, "idempotency_repo", None)
87
+ if not repo:
88
+ # If repo isn't configured, degrade gracefully or fail.
89
+ return await call_next(request)
90
+
91
+ # 1. Check if already executed
92
+ result = await repo.get(idem_key, user_id)
93
+ if result:
94
+ state, cached_response = result
95
+ if state == "IN_PROGRESS":
96
+ return JSONResponse(
97
+ status_code=status.HTTP_409_CONFLICT,
98
+ content={"detail": "Request with this Idempotency-Key is already in progress."}
99
+ )
100
+ if state == "COMPLETED" and cached_response:
101
+ return JSONResponse(
102
+ status_code=cached_response.status_code,
103
+ content=json.loads(cached_response.body) if cached_response.body else None,
104
+ headers=cached_response.headers
105
+ )
106
+
107
+ # 2. Acquire lock
108
+ acquired = await repo.lock(idem_key, user_id)
109
+ if not acquired:
110
+ return JSONResponse(
111
+ status_code=status.HTTP_409_CONFLICT,
112
+ content={"detail": "Concurrent request with this Idempotency-Key detected."}
113
+ )
114
+
115
+ # 3. Execute
116
+ response = await call_next(request)
117
+
118
+ # 4. Cache successful responses (2xx)
119
+ if 200 <= response.status_code < 300:
120
+ # To cache the body, we have to extract it, which is complex in ASGI.
121
+ # For simplicity in this scaffold, we store a basic body or use custom routers.
122
+ # Real robust implementation should buffer the ASGI chunks.
123
+ # We'll just cache the status here for demonstration.
124
+ resp_to_cache = IdempotencyResponse(
125
+ status_code=response.status_code,
126
+ headers=dict(response.headers),
127
+ body='{"status": "completed"}' # Mocked for middleware.
128
+ )
129
+ await repo.save(idem_key, user_id, resp_to_cache)
130
+
131
+ return response
@@ -0,0 +1,37 @@
1
+ from fastapi import APIRouter, Depends, Query
2
+ from pydantic import BaseModel
3
+ from typing import Optional
4
+ from <%= packageName %>.core.service.example_service import ExampleService
5
+ from <%= packageName %>.entrypoints.api.dependencies import get_example_service
6
+
7
+ router = APIRouter(prefix="/examples", tags=["examples"])
8
+
9
+ class CreateExampleRequest(BaseModel):
10
+ name: str
11
+
12
+ @router.post("")
13
+ async def create_example(
14
+ request: CreateExampleRequest,
15
+ service: ExampleService = Depends(get_example_service)
16
+ ):
17
+ entity = await service.create_example(name=request.name)
18
+ return entity
19
+
20
+ <% if (postgres) { %>
21
+ @router.get("/{entity_id}")
22
+ async def get_example(
23
+ entity_id: str,
24
+ service: ExampleService = Depends(get_example_service)
25
+ ):
26
+ entity = await service.get_example(entity_id)
27
+ return entity
28
+
29
+ @router.get("")
30
+ async def list_examples(
31
+ limit: int = Query(10, ge=1, le=100),
32
+ cursor: Optional[str] = None,
33
+ service: ExampleService = Depends(get_example_service)
34
+ ):
35
+ result = await service.list_examples(limit=limit, cursor=cursor)
36
+ return result
37
+ <% } %>
@@ -0,0 +1,20 @@
1
+ from fastapi import APIRouter, WebSocket, WebSocketDisconnect, Depends
2
+ from <%= packageName %>.adapters.websocket_hub import WebSocketHub
3
+
4
+ # Instantiate hub (in a real app, bind to app state in lifespan)
5
+ hub = WebSocketHub()
6
+
7
+ router = APIRouter(prefix="/ws", tags=["websocket"])
8
+
9
+ @router.websocket("")
10
+ async def websocket_endpoint(websocket: WebSocket):
11
+ await hub.connect(websocket)
12
+ try:
13
+ # Subscribe to a default channel or read from query
14
+ await hub.subscribe("global")
15
+ while True:
16
+ data = await websocket.receive_text()
17
+ # Handle incoming data if needed
18
+ await hub.broadcast("global", {"echo": data})
19
+ except WebSocketDisconnect:
20
+ hub.disconnect(websocket)