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.
- package/CHANGELOG.md +781 -0
- package/LICENSE +21 -0
- package/README.md +44 -29
- package/bin/groundwork.js +1654 -0
- package/dist/src/generators/add-capability/generator.d.ts +8 -0
- package/dist/src/generators/add-capability/generator.js +60 -0
- package/dist/src/generators/add-capability/generator.js.map +1 -0
- package/dist/src/generators/cli-app/generator.d.ts +9 -0
- package/dist/src/generators/cli-app/generator.js +140 -0
- package/dist/src/generators/cli-app/generator.js.map +1 -0
- package/dist/src/generators/docs-site/generator.d.ts +5 -0
- package/dist/src/generators/docs-site/generator.js +441 -0
- package/dist/src/generators/docs-site/generator.js.map +1 -0
- package/dist/src/generators/electron-app/generator.d.ts +6 -0
- package/dist/src/generators/electron-app/generator.js +261 -0
- package/dist/src/generators/electron-app/generator.js.map +1 -0
- package/dist/src/generators/flutter-app/generator.d.ts +6 -0
- package/dist/src/generators/flutter-app/generator.js +314 -0
- package/dist/src/generators/flutter-app/generator.js.map +1 -0
- package/dist/src/generators/go-microservice/generator.d.ts +8 -0
- package/dist/src/generators/go-microservice/generator.js +232 -0
- package/dist/src/generators/go-microservice/generator.js.map +1 -0
- package/dist/src/generators/nextjs-app/generator.d.ts +8 -0
- package/dist/src/generators/nextjs-app/generator.js +294 -0
- package/dist/src/generators/nextjs-app/generator.js.map +1 -0
- package/dist/src/generators/python-microservice/generator.d.ts +13 -0
- package/dist/src/generators/python-microservice/generator.js +265 -0
- package/dist/src/generators/python-microservice/generator.js.map +1 -0
- package/dist/src/generators/shared/brand-tokens.d.ts +89 -0
- package/dist/src/generators/shared/brand-tokens.js +308 -0
- package/dist/src/generators/shared/brand-tokens.js.map +1 -0
- package/dist/src/generators/shared/capabilities.d.ts +101 -0
- package/dist/src/generators/shared/capabilities.js +279 -0
- package/dist/src/generators/shared/capabilities.js.map +1 -0
- package/dist/src/generators/shared/provenance.d.ts +2 -0
- package/dist/src/generators/shared/provenance.js +85 -0
- package/dist/src/generators/shared/provenance.js.map +1 -0
- package/dist/src/generators/shared/scaffold-helpers.d.ts +72 -0
- package/dist/src/generators/shared/scaffold-helpers.js +309 -0
- package/dist/src/generators/shared/scaffold-helpers.js.map +1 -0
- package/dist/src/generators/system-test-runner/generator.d.ts +23 -0
- package/dist/src/generators/system-test-runner/generator.js +125 -0
- package/dist/src/generators/system-test-runner/generator.js.map +1 -0
- package/dist/src/generators/workspace-dev-cli/generator.d.ts +7 -0
- package/dist/src/generators/workspace-dev-cli/generator.js +138 -0
- package/dist/src/generators/workspace-dev-cli/generator.js.map +1 -0
- package/generators.json +57 -0
- package/lib/repo-map/grammars/tree-sitter-c.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-cpp.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-csharp.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-dart.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-go.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-java.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-javascript.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-kotlin.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-lua.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-php.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-python.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-ruby.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-rust.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-scala.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-swift.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-tsx.wasm +0 -0
- package/lib/repo-map/grammars/tree-sitter-typescript.wasm +0 -0
- package/lib/repo-map/index.js +386 -0
- package/lib/repo-map/languages.js +514 -0
- package/lib/repo-map/pagerank.js +59 -0
- package/migrations/README.md +60 -0
- package/migrations/_template/cli-migration.js +27 -0
- package/migrations/gw-bet-prose-redesign.js +105 -0
- package/migrations/gw-drop-test-manifest.js +37 -0
- package/migrations/gw-register-serena-mcp.js +42 -0
- package/migrations/gw-relocate-hidden-skills.js +40 -0
- package/migrations/gw-seed-config-toml.js +24 -0
- package/migrations/index.json +40 -0
- package/package.json +70 -6
- package/src/AGENTS.md +36 -0
- package/src/config/config.toml +30 -0
- package/src/config/groundwork-state.json +5 -0
- package/src/docs/llms.txt +72 -0
- package/src/docs/principles/ai-native/agent-native-systems.md +90 -0
- package/src/docs/principles/ai-native/agentic-systems.md +78 -0
- package/src/docs/principles/ai-native/ai-engineering.md +100 -0
- package/src/docs/principles/ai-native/ai-native-product.md +76 -0
- package/src/docs/principles/delivery/cost-engineering.md +89 -0
- package/src/docs/principles/delivery/day-2-operational-baseline.md +57 -0
- package/src/docs/principles/delivery/devex.md +88 -0
- package/src/docs/principles/delivery/platform.md +101 -0
- package/src/docs/principles/delivery/progressive-delivery.md +92 -0
- package/src/docs/principles/design/ai-native-design.md +73 -0
- package/src/docs/principles/design/design-foundations.md +80 -0
- package/src/docs/principles/design/design-systems-and-tokens.md +72 -0
- package/src/docs/principles/design/interaction-and-motion.md +69 -0
- package/src/docs/principles/design/layout-and-space.md +72 -0
- package/src/docs/principles/design/usability-and-ux.md +68 -0
- package/src/docs/principles/design/visual-design.md +84 -0
- package/src/docs/principles/foundations/code-craft.md +86 -0
- package/src/docs/principles/foundations/continuous-discovery.md +75 -0
- package/src/docs/principles/foundations/documentation.md +102 -0
- package/src/docs/principles/foundations/prioritization-and-appetite.md +78 -0
- package/src/docs/principles/foundations/product-engineering.md +90 -0
- package/src/docs/principles/foundations/product-risks.md +89 -0
- package/src/docs/principles/foundations/requirements-and-specs.md +80 -0
- package/src/docs/principles/foundations/success-metrics.md +66 -0
- package/src/docs/principles/foundations/testing.md +82 -0
- package/src/docs/principles/index.md +23 -0
- package/src/docs/principles/quality/accessibility.md +88 -0
- package/src/docs/principles/quality/observability.md +84 -0
- package/src/docs/principles/quality/performance.md +84 -0
- package/src/docs/principles/quality/privacy.md +92 -0
- package/src/docs/principles/quality/reliability.md +89 -0
- package/src/docs/principles/quality/security.md +78 -0
- package/src/docs/principles/stack/postgres.md +100 -0
- package/src/docs/principles/system-design/api-design.md +86 -0
- package/src/docs/principles/system-design/architecture-decisions.md +81 -0
- package/src/docs/principles/system-design/code-structure.md +104 -0
- package/src/docs/principles/system-design/data-engineering.md +87 -0
- package/src/docs/principles/system-design/durable-execution.md +89 -0
- package/src/docs/principles/system-design/evolutionary-architecture.md +81 -0
- package/src/docs/principles/system-design/identity-and-access.md +76 -0
- package/src/docs/principles/system-design/integration-patterns.md +84 -0
- package/src/docs/principles/system-design/real-time.md +83 -0
- package/src/docs/principles/system-design/surface-architecture.md +74 -0
- package/src/docs/ways-of-working/documentation.md +69 -0
- package/src/docs/ways-of-working/how-we-work.md +76 -0
- package/src/docs/ways-of-working/units-of-work.md +40 -0
- package/src/engineer-skills/groundwork-electron-engineer/SKILL.md +118 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/ipc-contracts.md +138 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/packaging-and-updates.md +82 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/process-model.md +94 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/security.md +107 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/testing-and-smoke.md +107 -0
- package/src/engineer-skills/groundwork-electron-engineer/references/theming-and-tokens.md +74 -0
- package/src/engineer-skills/groundwork-electron-engineer/sync-anchor.md +14 -0
- package/src/engineer-skills/groundwork-flutter-engineer/SKILL.md +108 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/accessibility.md +92 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/architecture.md +189 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/data-and-contracts.md +136 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/navigation.md +122 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/platform-channels.md +93 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/releases-and-distribution.md +84 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/state-management.md +166 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/testing.md +135 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/theming-and-design-tokens.md +109 -0
- package/src/engineer-skills/groundwork-flutter-engineer/references/widgets-and-composition.md +123 -0
- package/src/engineer-skills/groundwork-flutter-engineer/sync-anchor.md +15 -0
- package/src/engineer-skills/groundwork-go-engineer/SKILL.md +171 -0
- package/src/engineer-skills/groundwork-go-engineer/references/api-design.md +82 -0
- package/src/engineer-skills/groundwork-go-engineer/references/architecture.md +42 -0
- package/src/engineer-skills/groundwork-go-engineer/references/capability-ports.md +50 -0
- package/src/engineer-skills/groundwork-go-engineer/references/code-craft-security.md +34 -0
- package/src/engineer-skills/groundwork-go-engineer/references/concurrency.md +108 -0
- package/src/engineer-skills/groundwork-go-engineer/references/go-services.md +77 -0
- package/src/engineer-skills/groundwork-go-engineer/references/http-handlers.md +172 -0
- package/src/engineer-skills/groundwork-go-engineer/references/implementation-patterns.md +156 -0
- package/src/engineer-skills/groundwork-go-engineer/references/integration-realtime-data.md +57 -0
- package/src/engineer-skills/groundwork-go-engineer/references/observability.md +49 -0
- package/src/engineer-skills/groundwork-go-engineer/references/postgres.md +41 -0
- package/src/engineer-skills/groundwork-go-engineer/references/reliability-performance.md +105 -0
- package/src/engineer-skills/groundwork-go-engineer/references/testing.md +139 -0
- package/src/engineer-skills/groundwork-go-engineer/sync-anchor.md +11 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/SKILL.md +107 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/architecture.md +323 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/data-fetching.md +458 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/documentation.md +324 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/error-boundaries.md +383 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/mutations-and-forms.md +396 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/performance-and-deployment.md +947 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/routing-and-navigation.md +405 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/server-components.md +394 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/tailwind-and-styling.md +134 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/testing.md +433 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/type-system.md +368 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/ux-principles.md +278 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/references/visual-language.md +69 -0
- package/src/engineer-skills/groundwork-nextjs-engineer/sync-anchor.md +9 -0
- package/src/engineer-skills/groundwork-python-engineer/SKILL.md +196 -0
- package/src/engineer-skills/groundwork-python-engineer/references/api-standards.md +88 -0
- package/src/engineer-skills/groundwork-python-engineer/references/architecture.md +57 -0
- package/src/engineer-skills/groundwork-python-engineer/references/async-patterns.md +103 -0
- package/src/engineer-skills/groundwork-python-engineer/references/capability-ports.md +44 -0
- package/src/engineer-skills/groundwork-python-engineer/references/database.md +88 -0
- package/src/engineer-skills/groundwork-python-engineer/references/documentation-mcp.md +167 -0
- package/src/engineer-skills/groundwork-python-engineer/references/implementation-patterns.md +166 -0
- package/src/engineer-skills/groundwork-python-engineer/references/ml-pipelines.md +119 -0
- package/src/engineer-skills/groundwork-python-engineer/references/ml-systems-ai-engineering.md +74 -0
- package/src/engineer-skills/groundwork-python-engineer/references/observability.md +57 -0
- package/src/engineer-skills/groundwork-python-engineer/references/resilience.md +126 -0
- package/src/engineer-skills/groundwork-python-engineer/references/testing.md +177 -0
- package/src/engineer-skills/groundwork-python-engineer/sync-anchor.md +13 -0
- package/src/generators/add-capability/generator.ts +70 -0
- package/src/generators/add-capability/schema.json +30 -0
- package/src/generators/capabilities/llm/capability.json +28 -0
- package/src/generators/capabilities/llm/providers/anthropic/footprint.json +13 -0
- package/src/generators/capabilities/llm/providers/anthropic/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/anthropic/stacks/python/src/__packageName__/adapters/llm.py.template +61 -0
- package/src/generators/capabilities/llm/providers/local/footprint.json +13 -0
- package/src/generators/capabilities/llm/providers/local/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/local/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
- package/src/generators/capabilities/llm/providers/localai/footprint.json +29 -0
- package/src/generators/capabilities/llm/providers/localai/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/localai/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
- package/src/generators/capabilities/llm/providers/none/footprint.json +9 -0
- package/src/generators/capabilities/llm/providers/none/stacks/go/internal/llm/llm.go.template +35 -0
- package/src/generators/capabilities/llm/providers/none/stacks/python/src/__packageName__/adapters/llm.py.template +25 -0
- package/src/generators/capabilities/llm/providers/ollama/footprint.json +20 -0
- package/src/generators/capabilities/llm/providers/ollama/stacks/go/internal/llm/llm.go.template +102 -0
- package/src/generators/capabilities/llm/providers/ollama/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
- package/src/generators/capabilities/llm/providers/openai/footprint.json +13 -0
- package/src/generators/capabilities/llm/providers/openai/stacks/go/internal/llm/llm.go.template +98 -0
- package/src/generators/capabilities/llm/providers/openai/stacks/python/src/__packageName__/adapters/llm.py.template +60 -0
- package/src/generators/capabilities/llm/stacks/go/internal/core/service/llm.go.template +12 -0
- package/src/generators/capabilities/llm/stacks/go/internal/llm/llm_test.go.template +33 -0
- package/src/generators/capabilities/llm/stacks/python/src/__packageName__/core/llm.py.template +15 -0
- package/src/generators/capabilities/llm/stacks/python/tests/contracts/test_llm.py.template +37 -0
- package/src/generators/cli-app/files/README.md.template +76 -0
- package/src/generators/cli-app/files/build.mjs.template +15 -0
- package/src/generators/cli-app/files/package.json.template +21 -0
- package/src/generators/cli-app/files/src/cli.ts.template +67 -0
- package/src/generators/cli-app/files/src/commands/hello.ts.template +17 -0
- package/src/generators/cli-app/files/src/commands/status.ts.template +23 -0
- package/src/generators/cli-app/files/src/core/client.test.ts.template +80 -0
- package/src/generators/cli-app/files/src/core/client.ts.template +64 -0
- package/src/generators/cli-app/files/src/registry.test.ts.template +35 -0
- package/src/generators/cli-app/files/src/registry.ts.template +31 -0
- package/src/generators/cli-app/files/tsconfig.json.template +16 -0
- package/src/generators/cli-app/files/tsconfig.test.json.template +11 -0
- package/src/generators/cli-app/generator.ts +138 -0
- package/src/generators/cli-app/schema.json +24 -0
- package/src/generators/docs-site/files/.gitignore.ejs +40 -0
- package/src/generators/docs-site/files/app/docs/__slug__/page.tsx +101 -0
- package/src/generators/docs-site/files/app/docs/layout.tsx +14 -0
- package/src/generators/docs-site/files/app/docs.css +43 -0
- package/src/generators/docs-site/files/app/layout.tsx +24 -0
- package/src/generators/docs-site/files/app/page.tsx +135 -0
- package/src/generators/docs-site/files/app/source.ts +8 -0
- package/src/generators/docs-site/files/components/mermaid.tsx +67 -0
- package/src/generators/docs-site/files/next.config.mjs +10 -0
- package/src/generators/docs-site/files/package.json +32 -0
- package/src/generators/docs-site/files/pnpm-workspace.yaml +7 -0
- package/src/generators/docs-site/files/postcss.config.mjs +6 -0
- package/src/generators/docs-site/files/source.config.ts +77 -0
- package/src/generators/docs-site/files/tailwind.config.js +10 -0
- package/src/generators/docs-site/files/tsconfig.json +27 -0
- package/src/generators/docs-site/generator.ts +476 -0
- package/src/generators/docs-site/schema.json +17 -0
- package/src/generators/electron-app/docs/principles/stack/electron/index.md +47 -0
- package/src/generators/electron-app/docs/principles/stack/electron/ipc-contracts.md +71 -0
- package/src/generators/electron-app/docs/principles/stack/electron/packaging-and-updates.md +59 -0
- package/src/generators/electron-app/docs/principles/stack/electron/process-model.md +53 -0
- package/src/generators/electron-app/docs/principles/stack/electron/security.md +70 -0
- package/src/generators/electron-app/docs/principles/stack/typescript/frontend.md +65 -0
- package/src/generators/electron-app/files/.gitignore.template +20 -0
- package/src/generators/electron-app/files/README.md.template +125 -0
- package/src/generators/electron-app/files/electron.vite.config.ts +31 -0
- package/src/generators/electron-app/files/eslint.config.mjs +92 -0
- package/src/generators/electron-app/files/forge.config.ts.template +44 -0
- package/src/generators/electron-app/files/package.json.template +54 -0
- package/src/generators/electron-app/files/playwright.config.ts +18 -0
- package/src/generators/electron-app/files/project.json.template +65 -0
- package/src/generators/electron-app/files/src/main/core-client.test.ts +81 -0
- package/src/generators/electron-app/files/src/main/core-client.ts +55 -0
- package/src/generators/electron-app/files/src/main/index.ts +157 -0
- package/src/generators/electron-app/files/src/main/ipc.ts +52 -0
- package/src/generators/electron-app/files/src/main/policy.test.ts +71 -0
- package/src/generators/electron-app/files/src/main/policy.ts +73 -0
- package/src/generators/electron-app/files/src/preload/index.ts +23 -0
- package/src/generators/electron-app/files/src/renderer/index.html.template +20 -0
- package/src/generators/electron-app/files/src/renderer/src/App.test.tsx +61 -0
- package/src/generators/electron-app/files/src/renderer/src/App.tsx.template +43 -0
- package/src/generators/electron-app/files/src/renderer/src/assets/main.css +40 -0
- package/src/generators/electron-app/files/src/renderer/src/env.d.ts +14 -0
- package/src/generators/electron-app/files/src/renderer/src/main.tsx +25 -0
- package/src/generators/electron-app/files/src/shared/ipc.ts +54 -0
- package/src/generators/electron-app/files/tests/smoke/app.spec.ts.template +68 -0
- package/src/generators/electron-app/files/tool/electron_exec.sh.template +83 -0
- package/src/generators/electron-app/files/tsconfig.json +7 -0
- package/src/generators/electron-app/files/tsconfig.node.json +27 -0
- package/src/generators/electron-app/files/tsconfig.web.json +22 -0
- package/src/generators/electron-app/files/vitest.config.ts +32 -0
- package/src/generators/electron-app/files/vitest.setup.ts +1 -0
- package/src/generators/electron-app/generator.ts +288 -0
- package/src/generators/electron-app/schema.json +23 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/architecture.md +78 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/index.md +38 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/platform-channels.md +51 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/releases-and-distribution.md +59 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/state-management.md +85 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/testing.md +74 -0
- package/src/generators/flutter-app/docs/principles/stack/flutter/widgets-and-composition.md +69 -0
- package/src/generators/flutter-app/files/.gitignore.template +30 -0
- package/src/generators/flutter-app/files/README.md.template +100 -0
- package/src/generators/flutter-app/files/analysis_options.yaml.template +18 -0
- package/src/generators/flutter-app/files/integration_test/app_test.dart.template +30 -0
- package/src/generators/flutter-app/files/lib/app.dart.template +24 -0
- package/src/generators/flutter-app/files/lib/config/app_config.dart +15 -0
- package/src/generators/flutter-app/files/lib/data/repositories/status_repository.dart +36 -0
- package/src/generators/flutter-app/files/lib/data/services/api_client.dart +71 -0
- package/src/generators/flutter-app/files/lib/domain/models/health_status.dart +23 -0
- package/src/generators/flutter-app/files/lib/main.dart +11 -0
- package/src/generators/flutter-app/files/lib/router.dart +23 -0
- package/src/generators/flutter-app/files/lib/ui/core/theme/app_theme.dart +110 -0
- package/src/generators/flutter-app/files/lib/ui/home/home_view.dart +89 -0
- package/src/generators/flutter-app/files/lib/ui/home/home_view_model.dart.template +38 -0
- package/src/generators/flutter-app/files/project.json.template +51 -0
- package/src/generators/flutter-app/files/pubspec.yaml.template +47 -0
- package/src/generators/flutter-app/files/test/api_client_test.dart.template +63 -0
- package/src/generators/flutter-app/files/test/fakes/fake_status_repository.dart.template +19 -0
- package/src/generators/flutter-app/files/test/home_view_test.dart.template +58 -0
- package/src/generators/flutter-app/files/tool/flutter_exec.sh.template +60 -0
- package/src/generators/flutter-app/generator.ts +362 -0
- package/src/generators/flutter-app/schema.json +23 -0
- package/src/generators/go-microservice/docs/principles/stack/go/concurrency.md +123 -0
- package/src/generators/go-microservice/docs/principles/stack/go/index.md +70 -0
- package/src/generators/go-microservice/docs/principles/stack/go/testing.md +152 -0
- package/src/generators/go-microservice/files/.air.toml.template +38 -0
- package/src/generators/go-microservice/files/.env.template +4 -0
- package/src/generators/go-microservice/files/.golangci.yml.template +82 -0
- package/src/generators/go-microservice/files/Dockerfile.dev.template +12 -0
- package/src/generators/go-microservice/files/asyncapi-pubsub.yaml.template +33 -0
- package/src/generators/go-microservice/files/asyncapi-ws.yaml.template +34 -0
- package/src/generators/go-microservice/files/cmd/api/main.go.template +149 -0
- package/src/generators/go-microservice/files/cmd/api/main_test.go.template +99 -0
- package/src/generators/go-microservice/files/cmd/worker/cleanup/main.go.template +39 -0
- package/src/generators/go-microservice/files/db/schema.sql.template +24 -0
- package/src/generators/go-microservice/files/go.mod.template +39 -0
- package/src/generators/go-microservice/files/internal/config/config.go.template +52 -0
- package/src/generators/go-microservice/files/internal/config/otel.go.template +93 -0
- package/src/generators/go-microservice/files/internal/core/domain/errors.go.template +16 -0
- package/src/generators/go-microservice/files/internal/core/domain/model.go.template +28 -0
- package/src/generators/go-microservice/files/internal/core/domain/user.go.template +13 -0
- package/src/generators/go-microservice/files/internal/core/pagination.go.template +16 -0
- package/src/generators/go-microservice/files/internal/core/service/app_service.go.template +79 -0
- package/src/generators/go-microservice/files/internal/core/service/event_hub.go.template +9 -0
- package/src/generators/go-microservice/files/internal/core/service/message_queue.go.template +10 -0
- package/src/generators/go-microservice/files/internal/core/service/outbox_repository.go.template +31 -0
- package/src/generators/go-microservice/files/internal/core/service/repository.go.template +23 -0
- package/src/generators/go-microservice/files/internal/core/service/user_repository.go.template +15 -0
- package/src/generators/go-microservice/files/internal/core/service/user_service.go.template +43 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/app_handler.go.template +108 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/auth_middleware_test.go.template +52 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook.go.template +202 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook_test.go.template +82 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/health_handler.go.template +80 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware.go.template +87 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware_test.go.template +76 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/repository.go.template +37 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_auth.go.template +40 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_loadshed.go.template +38 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_logging.go.template +40 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_ratelimit.go.template +48 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_test.go.template +81 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/router.go.template +105 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/types.go.template +70 -0
- package/src/generators/go-microservice/files/internal/entrypoints/api/websocket_handler.go.template +39 -0
- package/src/generators/go-microservice/files/internal/httpclient/http_client.go.template +87 -0
- package/src/generators/go-microservice/files/internal/kafka/kafka.go.template +34 -0
- package/src/generators/go-microservice/files/internal/postgres/postgres.go.template +195 -0
- package/src/generators/go-microservice/files/internal/postgres/postgres_test.go.template +156 -0
- package/src/generators/go-microservice/files/internal/postgres/user_repository.go.template +56 -0
- package/src/generators/go-microservice/files/internal/pubsub/gcp_pubsub.go.template +35 -0
- package/src/generators/go-microservice/files/internal/websocket/client.go.template +151 -0
- package/src/generators/go-microservice/files/internal/websocket/hub.go.template +261 -0
- package/src/generators/go-microservice/files/scripts/apply-schema.sh.template +21 -0
- package/src/generators/go-microservice/files/tools/tools.go.template +10 -0
- package/src/generators/go-microservice/generator.ts +240 -0
- package/src/generators/go-microservice/schema.json +63 -0
- package/src/generators/nextjs-app/docs/principles/stack/typescript/frontend.md +65 -0
- package/src/generators/nextjs-app/files/.dockerignore.template +7 -0
- package/src/generators/nextjs-app/files/.env.example.template +24 -0
- package/src/generators/nextjs-app/files/.gitignore.template +5 -0
- package/src/generators/nextjs-app/files/Dockerfile +53 -0
- package/src/generators/nextjs-app/files/app/(auth)/sign-in/__sign-in__/page.tsx.template +9 -0
- package/src/generators/nextjs-app/files/app/(auth)/sign-up/__sign-up__/page.tsx.template +9 -0
- package/src/generators/nextjs-app/files/app/api/config/route.ts.template +39 -0
- package/src/generators/nextjs-app/files/app/api/healthz/route.test.ts +15 -0
- package/src/generators/nextjs-app/files/app/api/healthz/route.ts +5 -0
- package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.test.ts.template +55 -0
- package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.ts.template +126 -0
- package/src/generators/nextjs-app/files/app/error.tsx +39 -0
- package/src/generators/nextjs-app/files/app/global-error.tsx +68 -0
- package/src/generators/nextjs-app/files/app/globals.css +105 -0
- package/src/generators/nextjs-app/files/app/layout.tsx +59 -0
- package/src/generators/nextjs-app/files/app/loading.tsx +13 -0
- package/src/generators/nextjs-app/files/app/not-found.tsx +30 -0
- package/src/generators/nextjs-app/files/app/page.tsx +20 -0
- package/src/generators/nextjs-app/files/components/providers/default.tsx +19 -0
- package/src/generators/nextjs-app/files/components/providers/production.tsx +32 -0
- package/src/generators/nextjs-app/files/components/providers/telemetry.tsx +76 -0
- package/src/generators/nextjs-app/files/components/render-smoke.test.tsx +29 -0
- package/src/generators/nextjs-app/files/components/theme-provider.tsx +11 -0
- package/src/generators/nextjs-app/files/components.json +21 -0
- package/src/generators/nextjs-app/files/eslint.config.mjs +120 -0
- package/src/generators/nextjs-app/files/hooks/use-toast.ts +7 -0
- package/src/generators/nextjs-app/files/instrumentation.ts +90 -0
- package/src/generators/nextjs-app/files/lib/api/fetcher.ts.template +130 -0
- package/src/generators/nextjs-app/files/lib/config.ts +21 -0
- package/src/generators/nextjs-app/files/lib/logger.ts +29 -0
- package/src/generators/nextjs-app/files/lib/schemas/index.ts +19 -0
- package/src/generators/nextjs-app/files/lib/utils.ts +6 -0
- package/src/generators/nextjs-app/files/next.config.mjs +9 -0
- package/src/generators/nextjs-app/files/package.json +70 -0
- package/src/generators/nextjs-app/files/postcss.config.mjs +8 -0
- package/src/generators/nextjs-app/files/proxy.test.ts.template +30 -0
- package/src/generators/nextjs-app/files/proxy.ts +31 -0
- package/src/generators/nextjs-app/files/public/.gitkeep +1 -0
- package/src/generators/nextjs-app/files/tsconfig.json +42 -0
- package/src/generators/nextjs-app/files/vitest.config.mts +15 -0
- package/src/generators/nextjs-app/files/vitest.setup.ts +7 -0
- package/src/generators/nextjs-app/generator.ts +307 -0
- package/src/generators/nextjs-app/schema.json +44 -0
- package/src/generators/python-microservice/docs/principles/stack/python/async.md +168 -0
- package/src/generators/python-microservice/docs/principles/stack/python/documentation.md +240 -0
- package/src/generators/python-microservice/docs/principles/stack/python/mcp.md +147 -0
- package/src/generators/python-microservice/docs/principles/stack/python/resilience.md +193 -0
- package/src/generators/python-microservice/docs/principles/stack/python/testing.md +281 -0
- package/src/generators/python-microservice/files/.env.example.template +30 -0
- package/src/generators/python-microservice/files/Dockerfile.template +36 -0
- package/src/generators/python-microservice/files/db/schema.sql.template +19 -0
- package/src/generators/python-microservice/files/pyproject.toml.template +76 -0
- package/src/generators/python-microservice/files/scripts/apply-schema.sh.template +25 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/comfyui.py.template +87 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/config.py.template +48 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/database.py.template +21 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/message_queue.py.template +29 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/repository.py.template +130 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/telemetry.py.template +68 -0
- package/src/generators/python-microservice/files/src/__packageName__/adapters/websocket_hub.py.template +36 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/domain/entities.py.template +22 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/domain/exceptions.py.template +43 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/ports.py.template +42 -0
- package/src/generators/python-microservice/files/src/__packageName__/core/service/example_service.py.template +68 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/dependencies.py.template +50 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/middleware.py.template +131 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/router.py.template +37 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/websocket_handler.py.template +20 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/cleanup.py.template +35 -0
- package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/worker.py.template +28 -0
- package/src/generators/python-microservice/files/src/__packageName__/main.py.template +108 -0
- package/src/generators/python-microservice/files/tests/test_main.py.template +74 -0
- package/src/generators/python-microservice/files/tests/test_middleware.py.template +109 -0
- package/src/generators/python-microservice/files/tests/test_worker.py.template +16 -0
- package/src/generators/python-microservice/generator.ts +286 -0
- package/src/generators/python-microservice/schema.json +86 -0
- package/src/generators/shared/brand-tokens.ts +301 -0
- package/src/generators/shared/capabilities.ts +349 -0
- package/src/generators/shared/provenance.ts +61 -0
- package/src/generators/shared/scaffold-helpers.ts +309 -0
- package/src/generators/system-test-runner/files/tests/bets/.gitkeep +0 -0
- package/src/generators/system-test-runner/files/tests/bets/_archive/.gitkeep +0 -0
- package/src/generators/system-test-runner/files/tests/conftest.py.template +503 -0
- package/src/generators/system-test-runner/files/tests/pyproject.toml.template +20 -0
- package/src/generators/system-test-runner/files/tests/system/pages/__init__.py.template +9 -0
- package/src/generators/system-test-runner/files/tests/system/pages/base_page.py.template +36 -0
- package/src/generators/system-test-runner/files/tests/system/test_a11y_smoke.py.template +132 -0
- package/src/generators/system-test-runner/files/tests/system/test_contract_conformance.py.template +140 -0
- package/src/generators/system-test-runner/files/tests/system/test_layout_geometry.py.template +109 -0
- package/src/generators/system-test-runner/files/tests/system/test_render_smoke.py.template +227 -0
- package/src/generators/system-test-runner/files/tests/system/test_system.py.template +158 -0
- package/src/generators/system-test-runner/files/tests/system/test_token_conformance.py.template +206 -0
- package/src/generators/system-test-runner/files/tests/system/test_visual_regression.py.template +104 -0
- package/src/generators/system-test-runner/generator.ts +142 -0
- package/src/generators/system-test-runner/schema.json +24 -0
- package/src/generators/workspace-dev-cli/cli-src/build.mjs +42 -0
- package/src/generators/workspace-dev-cli/cli-src/dist/dev-bundle.js +2168 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/bet.ts +442 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/completion.ts +87 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/doctor.ts +139 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/lifecycle.ts +548 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/quality.ts +127 -0
- package/src/generators/workspace-dev-cli/cli-src/src/commands/surface.ts +214 -0
- package/src/generators/workspace-dev-cli/cli-src/src/index.ts +127 -0
- package/src/generators/workspace-dev-cli/cli-src/src/registry.ts +194 -0
- package/src/generators/workspace-dev-cli/cli-src/src/theme/color.ts +130 -0
- package/src/generators/workspace-dev-cli/cli-src/src/theme/render.ts +158 -0
- package/src/generators/workspace-dev-cli/cli-src/src/theme/tokens.ts +122 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/context.ts +43 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/extensions.ts +99 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/paths.ts +46 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/proc.ts +106 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/prompt.ts +108 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/runners.ts +70 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/services.ts +221 -0
- package/src/generators/workspace-dev-cli/cli-src/src/util/version.ts +21 -0
- package/src/generators/workspace-dev-cli/cli-src/tsconfig.json +16 -0
- package/src/generators/workspace-dev-cli/files/.agents/skills/workspace-cli/SKILL.md.template +74 -0
- package/src/generators/workspace-dev-cli/files/dev.template +16 -0
- package/src/generators/workspace-dev-cli/files/docker-compose.yml.template +20 -0
- package/src/generators/workspace-dev-cli/files/scripts/cli/templates/milestone-test.pytmpl.template +46 -0
- package/src/generators/workspace-dev-cli/files/scripts/cli/templates/slice-test.pytmpl.template +38 -0
- package/src/generators/workspace-dev-cli/generator.ts +136 -0
- package/src/generators/workspace-dev-cli/schema.json +22 -0
- package/src/hidden-skills/code-intelligence.md +129 -0
- package/src/hidden-skills/groundwork-architect/SKILL.md +114 -0
- package/src/hidden-skills/groundwork-architect/references/agentic-systems.md +44 -0
- package/src/hidden-skills/groundwork-architect/references/ai-native-architecture.md +37 -0
- package/src/hidden-skills/groundwork-architect/references/api-and-contracts.md +45 -0
- package/src/hidden-skills/groundwork-architect/references/core-and-boundaries.md +45 -0
- package/src/hidden-skills/groundwork-architect/references/data-architecture.md +33 -0
- package/src/hidden-skills/groundwork-architect/references/decision-records.md +34 -0
- package/src/hidden-skills/groundwork-architect/references/durable-execution.md +45 -0
- package/src/hidden-skills/groundwork-architect/references/evolutionary-architecture.md +37 -0
- package/src/hidden-skills/groundwork-architect/references/identity-and-access.md +41 -0
- package/src/hidden-skills/groundwork-architect/references/integration-patterns.md +39 -0
- package/src/hidden-skills/groundwork-architect/references/observability.md +36 -0
- package/src/hidden-skills/groundwork-architect/references/performance-and-scale.md +41 -0
- package/src/hidden-skills/groundwork-architect/references/platform-and-delivery.md +47 -0
- package/src/hidden-skills/groundwork-architect/references/realtime-and-async.md +28 -0
- package/src/hidden-skills/groundwork-architect/references/reliability.md +31 -0
- package/src/hidden-skills/groundwork-architect/references/security-and-trust.md +47 -0
- package/src/hidden-skills/groundwork-architect/references/surface-architecture.md +40 -0
- package/src/hidden-skills/groundwork-architect/sync-anchor.md +34 -0
- package/src/hidden-skills/groundwork-architecture/architecture-template.md +50 -0
- package/src/hidden-skills/groundwork-architecture/instructions.md +139 -0
- package/src/hidden-skills/groundwork-architecture/phases/01-context-ingestion.md +18 -0
- package/src/hidden-skills/groundwork-architecture/phases/02-technical-constraints.md +27 -0
- package/src/hidden-skills/groundwork-architecture/phases/03-service-design.md +19 -0
- package/src/hidden-skills/groundwork-architecture/phases/04-data-flow-communication.md +23 -0
- package/src/hidden-skills/groundwork-architecture/phases/05-component-boundaries-contracts.md +17 -0
- package/src/hidden-skills/groundwork-architecture/phases/06-draft-review-present.md +38 -0
- package/src/hidden-skills/groundwork-architecture/phases/07-commit.md +33 -0
- package/src/hidden-skills/groundwork-architecture/templates/architecture-cache.md +43 -0
- package/src/hidden-skills/groundwork-architecture-extract/instructions.md +163 -0
- package/src/hidden-skills/groundwork-architecture-extract/templates/architecture-extract-cache.md +21 -0
- package/src/hidden-skills/groundwork-bet/briefs/slice-worker.md +191 -0
- package/src/hidden-skills/groundwork-bet/instructions.md +88 -0
- package/src/hidden-skills/groundwork-bet/templates/bet-progress-test.md +126 -0
- package/src/hidden-skills/groundwork-bet/templates/change-proposal.md +38 -0
- package/src/hidden-skills/groundwork-bet/templates/decomposition/meta.json +4 -0
- package/src/hidden-skills/groundwork-bet/templates/decomposition/milestone-index.md +35 -0
- package/src/hidden-skills/groundwork-bet/templates/decomposition/slice.md +35 -0
- package/src/hidden-skills/groundwork-bet/templates/pitch.md +45 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/01-ui-design.md +51 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/02-data-flows.md +36 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/03-api-design.md +90 -0
- package/src/hidden-skills/groundwork-bet/templates/technical-design/04-data-design.md +29 -0
- package/src/hidden-skills/groundwork-bet/workflows/01-discovery.md +198 -0
- package/src/hidden-skills/groundwork-bet/workflows/02-design.md +168 -0
- package/src/hidden-skills/groundwork-bet/workflows/03-decomposition.md +246 -0
- package/src/hidden-skills/groundwork-bet/workflows/04-delivery.md +193 -0
- package/src/hidden-skills/groundwork-bet/workflows/05-validation.md +199 -0
- package/src/hidden-skills/groundwork-design-system/instructions.md +125 -0
- package/src/hidden-skills/groundwork-design-system/templates/brand-tokens.md +182 -0
- package/src/hidden-skills/groundwork-design-system/templates/design-system-cache.md +64 -0
- package/src/hidden-skills/groundwork-design-system/tracks/_foundation.md +136 -0
- package/src/hidden-skills/groundwork-design-system/tracks/agentic-protocol.md +269 -0
- package/src/hidden-skills/groundwork-design-system/tracks/cli.md +355 -0
- package/src/hidden-skills/groundwork-design-system/tracks/graphical-ui.md +330 -0
- package/src/hidden-skills/groundwork-design-system-extract/instructions.md +124 -0
- package/src/hidden-skills/groundwork-design-system-extract/templates/design-system-extract-cache.md +19 -0
- package/src/hidden-skills/groundwork-designer/SKILL.md +108 -0
- package/src/hidden-skills/groundwork-designer/references/accessibility.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/ai-native-design.md +37 -0
- package/src/hidden-skills/groundwork-designer/references/design-review.md +29 -0
- package/src/hidden-skills/groundwork-designer/references/design-systems-and-tokens.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/interaction-and-motion.md +37 -0
- package/src/hidden-skills/groundwork-designer/references/layout-and-space.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/usability-and-ux.md +33 -0
- package/src/hidden-skills/groundwork-designer/references/visual-craft.md +49 -0
- package/src/hidden-skills/groundwork-designer/sync-anchor.md +20 -0
- package/src/hidden-skills/groundwork-doc-sync/instructions.md +100 -0
- package/src/hidden-skills/groundwork-elicit/instructions.md +66 -0
- package/src/hidden-skills/groundwork-elicit/methods.md +65 -0
- package/src/hidden-skills/groundwork-infra-adopt/instructions.md +168 -0
- package/src/hidden-skills/groundwork-infra-adopt/templates/infra-adopt-cache.md +21 -0
- package/src/hidden-skills/groundwork-mvp/instructions.md +223 -0
- package/src/hidden-skills/groundwork-mvp/templates/mvp-cache.md +9 -0
- package/src/hidden-skills/groundwork-patch/instructions.md +40 -0
- package/src/hidden-skills/groundwork-persona/instructions.md +54 -0
- package/src/hidden-skills/groundwork-product/SKILL.md +102 -0
- package/src/hidden-skills/groundwork-product/references/ai-native-product.md +45 -0
- package/src/hidden-skills/groundwork-product/references/discovery-and-opportunity.md +38 -0
- package/src/hidden-skills/groundwork-product/references/product-risks.md +52 -0
- package/src/hidden-skills/groundwork-product/references/requirements-and-specs.md +39 -0
- package/src/hidden-skills/groundwork-product/references/scope-and-sequencing.md +35 -0
- package/src/hidden-skills/groundwork-product/references/shaping-and-appetite.md +48 -0
- package/src/hidden-skills/groundwork-product/references/success-metrics-and-signals.md +37 -0
- package/src/hidden-skills/groundwork-product/sync-anchor.md +19 -0
- package/src/hidden-skills/groundwork-product-brief/instructions.md +231 -0
- package/src/hidden-skills/groundwork-product-brief-extract/instructions.md +139 -0
- package/src/hidden-skills/groundwork-product-brief-extract/templates/product-brief-extract-cache.md +17 -0
- package/src/hidden-skills/groundwork-review/checklists/architecture.md +93 -0
- package/src/hidden-skills/groundwork-review/checklists/bet-pitch.md +94 -0
- package/src/hidden-skills/groundwork-review/checklists/decomposition.md +135 -0
- package/src/hidden-skills/groundwork-review/checklists/design-system.md +85 -0
- package/src/hidden-skills/groundwork-review/checklists/domain-entity.md +66 -0
- package/src/hidden-skills/groundwork-review/checklists/implementation-readiness.md +46 -0
- package/src/hidden-skills/groundwork-review/checklists/infrastructure.md +68 -0
- package/src/hidden-skills/groundwork-review/checklists/maturity.md +71 -0
- package/src/hidden-skills/groundwork-review/checklists/product-brief.md +69 -0
- package/src/hidden-skills/groundwork-review/checklists/technical-design.md +112 -0
- package/src/hidden-skills/groundwork-review/instructions.md +181 -0
- package/src/hidden-skills/groundwork-scaffold/instructions.md +254 -0
- package/src/hidden-skills/groundwork-scaffold/phases/01-ingestion-service-mapping.md +87 -0
- package/src/hidden-skills/groundwork-scaffold/phases/02-scaffolding-execution.md +15 -0
- package/src/hidden-skills/groundwork-scaffold/phases/03-service-documentation-api-stubs.md +100 -0
- package/src/hidden-skills/groundwork-scaffold/phases/04-infrastructure-verification.md +17 -0
- package/src/hidden-skills/groundwork-scaffold/phases/05-draft-review.md +19 -0
- package/src/hidden-skills/groundwork-scaffold/phases/06-commit.md +19 -0
- package/src/hidden-skills/groundwork-scaffold/templates/scaffold-cache.md +23 -0
- package/src/hidden-skills/groundwork-scan/instructions.md +164 -0
- package/src/hidden-skills/groundwork-scan/references/digest-schema.md +66 -0
- package/src/hidden-skills/groundwork-scan/references/exclusions.md +44 -0
- package/src/hidden-skills/groundwork-scan/templates/architecture-findings.md +42 -0
- package/src/hidden-skills/groundwork-scan/templates/design-findings.md +23 -0
- package/src/hidden-skills/groundwork-scan/templates/overview.md +26 -0
- package/src/hidden-skills/groundwork-scan/templates/product-findings.md +23 -0
- package/src/hidden-skills/groundwork-scan/templates/scan-state.json +19 -0
- package/src/hidden-skills/groundwork-stack-forge/instructions.md +150 -0
- package/src/hidden-skills/groundwork-stack-forge/references/authoring-engineer-skills.md +107 -0
- package/src/hidden-skills/groundwork-surface-activation/instructions.md +138 -0
- package/src/hidden-skills/groundwork-update/briefs/reconcile-worker.md +196 -0
- package/src/hidden-skills/groundwork-update/instructions.md +200 -0
- package/src/hidden-skills/groundwork-writer/SKILL.md +278 -0
- package/src/hidden-skills/maturity-model.md +125 -0
- package/src/hidden-skills/operating-contract.md +400 -0
- package/src/hidden-skills/repo-map-schema.md +90 -0
- package/src/hidden-skills/templates/adr.md +57 -0
- package/src/hidden-skills/templates/capability-ports.md +71 -0
- package/src/hidden-skills/templates/discovery-notes.md +33 -0
- package/src/hidden-skills/templates/domain-entity.md +80 -0
- package/src/hidden-skills/templates/gap-ledger.md +21 -0
- package/src/hidden-skills/templates/handoff.md +37 -0
- package/src/hidden-skills/templates/maturity.md +39 -0
- package/src/hidden-skills/templates/surfaces.md +207 -0
- package/src/skills/groundwork-check/SKILL.md +56 -0
- package/src/skills/groundwork-check/instructions.md +70 -0
- package/src/skills/groundwork-orchestrator/SKILL.md +176 -0
- package/src/skills/groundwork-orchestrator/workflow-index.md +50 -0
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Testing
|
|
3
|
+
description: Unit, widget, and integration test taxonomy; headless Android emulator CI; Patrol for native boundaries; alchemist goldens; the prove-once rule.
|
|
4
|
+
status: active
|
|
5
|
+
last_reviewed: 2026-06-12
|
|
6
|
+
---
|
|
7
|
+
# Testing
|
|
8
|
+
|
|
9
|
+
## TL;DR
|
|
10
|
+
|
|
11
|
+
Three tiers: pure-Dart unit tests with fakes, widget tests as the bulk of coverage, and `integration_test` happy paths on a headless Android emulator as the CI-canonical loop. Patrol enters only when a flow crosses the Flutter/OS boundary. Goldens run via alchemist. Surface tests assert wiring, rendering, and interaction — they never re-prove business logic already proven at the core's contract.
|
|
12
|
+
|
|
13
|
+
## Why this matters
|
|
14
|
+
|
|
15
|
+
Flutter's first-party test harness is the reason Flutter is GroundWork's mobile pick: `flutter test` runs widget tests headless in seconds, and `integration_test` drives the real app on a headless emulator — the agent runs generate → boot → test → observe without a human holding a device. The agent-closable loop axis lives or dies in this file. Every choice below protects that loop: fakes over mocks keep unit tests refactor-stable, the emulator lane stays thin because surface tests are wiring-only, and iOS never gates CI because an iOS simulator needs macOS runners and hands.
|
|
16
|
+
|
|
17
|
+
## The prove-once principle
|
|
18
|
+
|
|
19
|
+
Capability behaviour is proven once, headless, at the core's contract. The Flutter surface proves only that it is **wired** to the core (the typed client is called with the right inputs), **renders** core state correctly, and **handles interaction** (commands fire, navigation moves, errors surface). A widget or integration test that re-asserts a business rule — price calculation, permission logic, validation semantics — is a review finding: it duplicates a proof that already exists at the contract and couples the surface suite to core internals. This is what keeps N surfaces affordable.
|
|
20
|
+
|
|
21
|
+
## The tiers
|
|
22
|
+
|
|
23
|
+
### Tier 1 — Unit tests (pure Dart)
|
|
24
|
+
|
|
25
|
+
View models, repositories, mappers — anything with logic and no widget. Dependencies are substituted with **fakes, not mocks** (the official guide strongly recommends this): an in-memory `FakeUserRepository` implementing the abstract class survives refactors that stub-and-verify mocks break on, and it doubles as the fixture for widget tests. Riverpod's `ProviderContainer` with overrides is the seam (see [State management](state-management.md)).
|
|
26
|
+
|
|
27
|
+
### Tier 2 — Widget tests (the bulk)
|
|
28
|
+
|
|
29
|
+
Most coverage lives here. `testWidgets` pumps the feature's View inside a `ProviderScope` with fake repositories, then asserts rendering and interaction through the semantics tree:
|
|
30
|
+
|
|
31
|
+
```dart
|
|
32
|
+
testWidgets('renaming updates the profile header', (tester) async {
|
|
33
|
+
await tester.pumpWidget(ProviderScope(
|
|
34
|
+
overrides: [userRepositoryProvider.overrideWithValue(fakeRepo)],
|
|
35
|
+
child: const MaterialApp(home: ProfileView()),
|
|
36
|
+
));
|
|
37
|
+
await tester.enterText(find.bySemanticsLabel('Name'), 'Ada');
|
|
38
|
+
await tester.tap(find.text('Save'));
|
|
39
|
+
await tester.pumpAndSettle();
|
|
40
|
+
expect(find.text('Ada'), findsOneWidget);
|
|
41
|
+
expect(fakeRepo.lastRename, 'Ada');
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Widget tests are fast, headless, and deterministic — they are the mobile analogue of the web stack's component tests, and they carry the rendering/interaction half of the surface proof. Find by semantics and visible text, not by widget type or internal keys, so tests assert what users perceive.
|
|
46
|
+
|
|
47
|
+
### Tier 3 — `integration_test` (happy-path E2E, CI-canonical)
|
|
48
|
+
|
|
49
|
+
A small set of happy-path flows through the real app binary — launch, sign in against a faked or staged core, exercise one flow per critical journey. These run **on a headless Android emulator in CI**: the standard pattern is `reactivecircus/android-emulator-runner@v2` (x86_64, `-no-window -gpu swiftshader_indirect -no-snapshot-load -no-snapshot-save`, KVM-enabled runner) executing `flutter test integration_test`.
|
|
50
|
+
|
|
51
|
+
**Android is the CI gate; iOS is a local-only lane.** The headless Android emulator is cheap, scriptable, and agent-drivable; iOS simulators need macOS runners and routinely need hands — putting them in the gate trades the agent-closable loop for platform symmetry the wiring proof does not need. iOS-specific verification happens locally or on device farms (Firebase Test Lab, Codemagic) as an explicit, non-gating lane.
|
|
52
|
+
|
|
53
|
+
Keep this tier thin. Every integration test is minutes of emulator time; if a widget test can carry the assertion, it does.
|
|
54
|
+
|
|
55
|
+
### Patrol — only across the Flutter/OS boundary
|
|
56
|
+
|
|
57
|
+
**Patrol** (LeanCode) is added only when a flow leaves Flutter for the OS: permission dialogs, push notifications, system sign-in sheets, WebViews, home-button/recents behaviour — surfaces `integration_test` structurally cannot touch. It also brings full test isolation and sharding. A Patrol suite duplicating pure-Flutter flows that `integration_test` already covers is scope creep; the boundary is the OS, not preference for its finder DSL.
|
|
58
|
+
|
|
59
|
+
### Golden tests — alchemist
|
|
60
|
+
|
|
61
|
+
Goldens guard design-system-level components (the token-projected theme made visible). Use **alchemist**, with its platform-test vs CI-test split — CI variants render text as blocks, killing the cross-platform font flakiness that made goldens a deletion candidate. `golden_toolkit` is discontinued — legacy; migrate, do not adopt. Golden scope is the component library, not full screens: screen-level goldens churn on every copy change and teach the team to rubber-stamp diffs.
|
|
62
|
+
|
|
63
|
+
## Legacy
|
|
64
|
+
|
|
65
|
+
`flutter_driver` (long deprecated for `integration_test`); `golden_toolkit`; Appium-first Flutter testing (a mixed-stack-org accommodation, not Flutter-native practice).
|
|
66
|
+
|
|
67
|
+
## Anti-patterns
|
|
68
|
+
|
|
69
|
+
- **Re-proving core logic on the surface.** The contract suite already proved it; the surface proves wiring.
|
|
70
|
+
- **Mock-heavy unit tests.** Stub-and-verify mocks test the mock's script. Fakes test behaviour.
|
|
71
|
+
- **iOS simulator as a CI gate.** It breaks the headless loop; keep it a local or device-farm lane.
|
|
72
|
+
- **Fat integration suites.** Emulator minutes are the most expensive test currency in this stack; spend them on happy paths only.
|
|
73
|
+
- **Finding by widget type or implementation keys.** Tests coupled to the widget tree break on refactor; semantics-based finds break on user-visible regressions only.
|
|
74
|
+
- **`pumpAndSettle` as a sleep.** If a test needs settling tricks to pass, the awaited state is not modelled; assert on it explicitly.
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Widgets and Composition
|
|
3
|
+
description: Composition over inheritance, const discipline, build purity, keys, token-projected theming, go_router navigation, and the accessibility baseline.
|
|
4
|
+
status: active
|
|
5
|
+
last_reviewed: 2026-06-12
|
|
6
|
+
---
|
|
7
|
+
# Widgets and Composition
|
|
8
|
+
|
|
9
|
+
## TL;DR
|
|
10
|
+
|
|
11
|
+
Widgets compose; they do not inherit. Build methods are pure, `const` is applied wherever the constructor allows, keys are used deliberately, and every colour, radius, and text style flows from a `ThemeData` module generated from the design system's brand tokens — never hand-rolled. Navigation is go_router with typed routes via `go_router_builder`. Accessibility is a merge gate, not a backlog item.
|
|
12
|
+
|
|
13
|
+
## Why this matters
|
|
14
|
+
|
|
15
|
+
Flutter's rendering model rewards exactly one style: small, pure, const-friendly widgets composed deeply. Every deviation — subclassed widgets, side effects in build, hardcoded colours — is a deviation an agent must special-case forever after. Keeping the widget layer mechanical is what keeps it cheap.
|
|
16
|
+
|
|
17
|
+
## The principles
|
|
18
|
+
|
|
19
|
+
### Composition over inheritance
|
|
20
|
+
|
|
21
|
+
New UI is built by composing existing widgets, never by subclassing a widget to alter its behaviour. A "PrimaryButton" wraps and configures; it does not extend. Extract a widget when a build method's subtree is reused or when it can become `const` — extraction into widgets (not helper methods returning widgets) is what gives Flutter subtree-level rebuild isolation.
|
|
22
|
+
|
|
23
|
+
### `const` discipline
|
|
24
|
+
|
|
25
|
+
Every widget constructor that can be `const` is `const`, and every instantiation site that can use `const` does. A `const` widget is canonicalised and skipped during rebuilds — this is the cheapest performance work in Flutter, it is enforced by lints (`prefer_const_constructors` and friends in `flutter_lints`), and it costs nothing at authoring time.
|
|
26
|
+
|
|
27
|
+
### Build purity
|
|
28
|
+
|
|
29
|
+
`build` reads state and returns widgets. It never mutates state, fires requests, shows dialogs, or starts animations — Flutter may call build at any frequency, and an impure build turns rebuild cadence into behaviour. Side effects belong in view-model commands, lifecycle hooks, or listeners.
|
|
30
|
+
|
|
31
|
+
### Keys are deliberate
|
|
32
|
+
|
|
33
|
+
Keys appear in exactly three situations: reordering children in lists (`ValueKey` on the item id), preserving state when the tree shape changes around a stateful widget, and `GlobalKey` for the rare imperative handle (forms). A key sprinkled "to be safe" is noise; a missing key on a reorderable list is a state-corruption bug.
|
|
34
|
+
|
|
35
|
+
### Theming is a projection, not an authoring surface
|
|
36
|
+
|
|
37
|
+
A GroundWork app's theme module is **generated from `brand-tokens.json`** — the design system's token file projects into a Dart theme module exposing `ThemeData` (and any semantic extensions via `ThemeExtension`). Widgets consume `Theme.of(context)` and the generated extensions; they never declare `Color(0xFF...)`, raw `TextStyle`s, or magic paddings. This is the one-design-system-projection dividend of the capability-core model: the same tokens drive every surface, so cross-surface visual consistency is a build artifact, not a review hope. A hex literal in a widget file is a review finding.
|
|
38
|
+
|
|
39
|
+
Note for planning: Material and Cupertino are frozen in the core framework as of Flutter 3.44, moving to standalone `material_ui`/`cupertino_ui` packages — theme code should expect that dependency shift.
|
|
40
|
+
|
|
41
|
+
### Navigation is go_router, typed
|
|
42
|
+
|
|
43
|
+
**go_router** (flutter.dev verified publisher, declared feature-complete — a stable platform piece, not a moving target) is the router:
|
|
44
|
+
|
|
45
|
+
- **Typed routes via `go_router_builder`** — route paths and parameters as generated, compile-checked classes. Stringly-typed `context.go('/user/$id')` calls scattered through features are the navigation equivalent of hand-rolled JSON.
|
|
46
|
+
- **`StatefulShellRoute`** for bottom-bar/tab scaffolds with per-tab navigation state.
|
|
47
|
+
- **Centralised `redirect`** for auth guards — one function, not per-screen checks.
|
|
48
|
+
- **Deep links fall out for free**: anything declared as a `GoRoute` is deep-linkable, which is also why the route is a first-class state container.
|
|
49
|
+
|
|
50
|
+
Raw Navigator 1.0 push/pop survives only for trivial local flows (a dialog, a one-off modal). Hand-rolled Navigator 2.0 `RouterDelegate` code is legacy — it is the API go_router exists to hide.
|
|
51
|
+
|
|
52
|
+
### Accessibility is a baseline
|
|
53
|
+
|
|
54
|
+
Every interactive widget has a semantic label (`Semantics`, `Tooltip`, or the widget's built-in semantics), tap targets meet the 48dp minimum, contrast meets WCAG AA via the token palette (enforced at the design-system layer, inherited here), and dynamic type does not break layouts — test at large text scales. Flutter's semantics tree is also the test seam: widget tests find by semantics, so inaccessible UI is untestable UI. Accessibility failures block merges.
|
|
55
|
+
|
|
56
|
+
## Anti-patterns we reject
|
|
57
|
+
|
|
58
|
+
- **Helper methods returning widget subtrees.** `Widget _buildHeader()` defeats const canonicalisation and rebuild isolation. Extract a widget class.
|
|
59
|
+
- **Hardcoded colours, text styles, or spacing.** The theme module is generated from tokens; literals fork the design system silently.
|
|
60
|
+
- **`MediaQuery.of(context).size` for layout decisions.** Use `LayoutBuilder` — MediaQuery couples a widget to the screen, not its parent's constraints.
|
|
61
|
+
- **Logic in build.** Conditionals that encode business rules belong in the view model; build renders state.
|
|
62
|
+
- **Stringly-typed navigation.** Generated route classes exist; use them.
|
|
63
|
+
- **GlobalKeys as state plumbing.** A GlobalKey reaching into another widget's state is a view model that wasn't written.
|
|
64
|
+
|
|
65
|
+
## Further reading
|
|
66
|
+
|
|
67
|
+
- [Flutter widget docs](https://docs.flutter.dev/ui) — the composition mental model.
|
|
68
|
+
- [go_router](https://pub.dev/packages/go_router) and [go_router_builder](https://pub.dev/packages/go_router_builder) — routing and typed routes.
|
|
69
|
+
- [Flutter accessibility](https://docs.flutter.dev/ui/accessibility-and-internationalization/accessibility) — the semantics tree and platform integrations.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Dart / Flutter
|
|
2
|
+
.dart_tool/
|
|
3
|
+
.packages
|
|
4
|
+
build/
|
|
5
|
+
.flutter-plugins
|
|
6
|
+
.flutter-plugins-dependencies
|
|
7
|
+
pubspec.lock
|
|
8
|
+
|
|
9
|
+
# Platform shells are bootstrapped (tool/flutter_exec.sh bootstrap) and then
|
|
10
|
+
# owned by the repo — commit android/ and ios/ once they exist. Their build
|
|
11
|
+
# intermediates stay out:
|
|
12
|
+
android/.gradle/
|
|
13
|
+
android/local.properties
|
|
14
|
+
android/app/.cxx/
|
|
15
|
+
ios/Pods/
|
|
16
|
+
ios/.symlinks/
|
|
17
|
+
ios/Flutter/ephemeral/
|
|
18
|
+
|
|
19
|
+
# Signing material never enters git
|
|
20
|
+
# (docs/principles/stack/flutter/releases-and-distribution.md)
|
|
21
|
+
*.keystore
|
|
22
|
+
*.jks
|
|
23
|
+
key.properties
|
|
24
|
+
*.p8
|
|
25
|
+
*.p12
|
|
26
|
+
*.mobileprovision
|
|
27
|
+
|
|
28
|
+
# IDE
|
|
29
|
+
.idea/
|
|
30
|
+
*.iml
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
# <%= name %>
|
|
2
|
+
|
|
3
|
+
A Flutter mobile surface scaffolded by GroundWork. It is a thin adapter over the
|
|
4
|
+
workspace's capability core: business logic lives behind the promoted contracts
|
|
5
|
+
and is proven there once; this app proves wiring, rendering, and interaction.
|
|
6
|
+
The architecture is the official Flutter two-layer MVVM model — Riverpod for
|
|
7
|
+
state and DI, go_router for navigation, a dio-based typed client as the
|
|
8
|
+
core-access seam. Flutter is GroundWork's standard mobile pick per its
|
|
9
|
+
surface-stack-selection principle (training-set fluency, the agent-closable
|
|
10
|
+
loop, the platform capability ceiling); the engineering principles this app
|
|
11
|
+
embodies live in `docs/principles/stack/flutter/`.
|
|
12
|
+
|
|
13
|
+
## Toolchain
|
|
14
|
+
|
|
15
|
+
The Flutter SDK is a **declared prerequisite, not an assumption**. Generation
|
|
16
|
+
required no SDK; everything below does. Every Nx target runs through
|
|
17
|
+
`tool/flutter_exec.sh`, which reports `flutter SDK not found — tier skipped`
|
|
18
|
+
instead of failing cryptically when the SDK is missing.
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx nx run <%= fileName %>:bootstrap # one-time: flutter create (android/ios shells) + pub get
|
|
22
|
+
npx nx run <%= fileName %>:run # flutter run against a device/emulator
|
|
23
|
+
npx nx run <%= fileName %>:analyze # flutter analyze
|
|
24
|
+
npx nx run <%= fileName %>:test # widget + unit tests (headless, fast)
|
|
25
|
+
npx nx run <%= fileName %>:test-integration # integration_test on an emulator
|
|
26
|
+
npx nx run <%= fileName %>:build # debug APK
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
This project lives on pubspec and the Dart toolchain, not npm — it is wired
|
|
30
|
+
into the Nx workspace through `project.json` run-commands targets and does
|
|
31
|
+
**not** join `docker-compose.yml` (a mobile app has no Docker boot; see the
|
|
32
|
+
testing principles for what "boots" means here).
|
|
33
|
+
|
|
34
|
+
## Structure
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
lib/
|
|
38
|
+
├── main.dart # ProviderScope root
|
|
39
|
+
├── app.dart # MaterialApp.router + theme projection
|
|
40
|
+
├── router.dart # go_router route table
|
|
41
|
+
├── config/app_config.dart # --dart-define configuration (API_BASE_URL)
|
|
42
|
+
├── ui/ # feature-first: one View + ViewModel per feature
|
|
43
|
+
│ ├── core/theme/
|
|
44
|
+
│ │ ├── brand_palette.dart # GENERATED from brand-tokens.json — do not hand-edit
|
|
45
|
+
│ │ └── app_theme.dart # ThemeData built from the palette
|
|
46
|
+
│ └── home/
|
|
47
|
+
│ ├── home_view.dart # widgets only
|
|
48
|
+
│ └── home_view_model.dart # state + commands
|
|
49
|
+
├── data/ # type-first: shared across features
|
|
50
|
+
│ ├── repositories/ # source of truth; abstract class + remote impl
|
|
51
|
+
│ └── services/ # stateless wrappers; the contract client lives here
|
|
52
|
+
└── domain/models/ # immutable models
|
|
53
|
+
test/ # unit + widget tests (the bulk of coverage)
|
|
54
|
+
integration_test/ # happy-path smoke for the emulator lane
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
See `docs/principles/stack/flutter/architecture.md` for why each piece sits
|
|
58
|
+
where it does.
|
|
59
|
+
|
|
60
|
+
## Theme: a projection, not an authoring surface
|
|
61
|
+
|
|
62
|
+
`lib/ui/core/theme/brand_palette.dart` is generated from
|
|
63
|
+
`.groundwork/config/brand-tokens.json` (the design system's `visual` block —
|
|
64
|
+
palette roles in both themes, typography families, base radius). Widgets
|
|
65
|
+
consume `Theme.of(context)` and the `StatusColors` extension; they never
|
|
66
|
+
declare `Color(0xFF...)` literals. Re-run the design system to evolve the
|
|
67
|
+
brand, then regenerate the palette to match. To make the typography families
|
|
68
|
+
render, bundle their font assets in `pubspec.yaml`.
|
|
69
|
+
|
|
70
|
+
## The core-access seam (contract-client tooling)
|
|
71
|
+
|
|
72
|
+
`lib/data/services/api_client.dart` is a **hand-rolled thin client** over the
|
|
73
|
+
workspace gateway: one method per promoted-contract operation, typed models in
|
|
74
|
+
`domain/models/`, repositories translating contract payloads into domain
|
|
75
|
+
models. This is the lightest path that consumes the promoted contract directly
|
|
76
|
+
and adds no JVM codegen dependency to the toolchain.
|
|
77
|
+
|
|
78
|
+
**When the contract surface grows** past a handful of operations, switch to
|
|
79
|
+
generated clients — `openapi_generator`'s `dart-dio` output against the
|
|
80
|
+
promoted `openapi.yaml` — and keep the seam where it is: repositories consume
|
|
81
|
+
the generated client, and nothing above the data layer changes. Re-implementing
|
|
82
|
+
a large promoted contract by hand is the defect the principles warn about
|
|
83
|
+
(`docs/principles/stack/flutter/architecture.md`).
|
|
84
|
+
|
|
85
|
+
The gateway URL arrives via `--dart-define=API_BASE_URL=...`
|
|
86
|
+
(default `http://localhost:4000`; the Android emulator reaches the host's
|
|
87
|
+
localhost at `http://10.0.2.2:4000`).
|
|
88
|
+
|
|
89
|
+
## Testing
|
|
90
|
+
|
|
91
|
+
Three tiers, per `docs/principles/stack/flutter/testing.md`:
|
|
92
|
+
|
|
93
|
+
1. **Unit** — pure Dart, fakes over mocks, `ProviderContainer` overrides.
|
|
94
|
+
2. **Widget** (`test/`) — the bulk: rendering and interaction through the
|
|
95
|
+
semantics tree, repositories faked at the provider seam.
|
|
96
|
+
3. **Integration** (`integration_test/`) — thin happy-path smoke; CI runs it
|
|
97
|
+
on a headless Android emulator. iOS is a local-only lane, never a CI gate.
|
|
98
|
+
|
|
99
|
+
Surface tests never re-prove core business logic — that proof lives at the
|
|
100
|
+
core's contract.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Lint policy for this surface. flutter_lints carries the const discipline and
|
|
2
|
+
# composition rules the stack principles require
|
|
3
|
+
# (docs/principles/stack/flutter/widgets-and-composition.md).
|
|
4
|
+
include: package:flutter_lints/flutter.yaml
|
|
5
|
+
|
|
6
|
+
analyzer:
|
|
7
|
+
language:
|
|
8
|
+
strict-casts: true
|
|
9
|
+
strict-inference: true
|
|
10
|
+
strict-raw-types: true
|
|
11
|
+
|
|
12
|
+
linter:
|
|
13
|
+
rules:
|
|
14
|
+
prefer_const_constructors: true
|
|
15
|
+
prefer_const_declarations: true
|
|
16
|
+
prefer_final_locals: true
|
|
17
|
+
avoid_print: true
|
|
18
|
+
require_trailing_commas: true
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
2
|
+
import 'package:flutter_test/flutter_test.dart';
|
|
3
|
+
import 'package:integration_test/integration_test.dart';
|
|
4
|
+
import 'package:<%= pubspecName %>/app.dart';
|
|
5
|
+
import 'package:<%= pubspecName %>/data/repositories/status_repository.dart';
|
|
6
|
+
|
|
7
|
+
import '../test/fakes/fake_status_repository.dart';
|
|
8
|
+
|
|
9
|
+
/// Boot-tier smoke: the real app binary launches and renders home on a
|
|
10
|
+
/// headless Android emulator — the CI-canonical loop. Keep this tier thin
|
|
11
|
+
/// (happy paths only); emulator minutes are the most expensive test currency
|
|
12
|
+
/// in this stack. The gateway is faked so the smoke proves boot + rendering,
|
|
13
|
+
/// not network reachability (docs/principles/stack/flutter/testing.md).
|
|
14
|
+
void main() {
|
|
15
|
+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
|
|
16
|
+
|
|
17
|
+
testWidgets('the app boots to the home view', (tester) async {
|
|
18
|
+
await tester.pumpWidget(
|
|
19
|
+
ProviderScope(
|
|
20
|
+
overrides: [
|
|
21
|
+
statusRepositoryProvider.overrideWithValue(FakeStatusRepository()),
|
|
22
|
+
],
|
|
23
|
+
child: const App(),
|
|
24
|
+
),
|
|
25
|
+
);
|
|
26
|
+
await tester.pumpAndSettle();
|
|
27
|
+
|
|
28
|
+
expect(find.text('Wired to the workspace gateway'), findsOneWidget);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import 'package:flutter/material.dart';
|
|
2
|
+
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
|
+
|
|
4
|
+
import 'router.dart';
|
|
5
|
+
import 'ui/core/theme/app_theme.dart';
|
|
6
|
+
|
|
7
|
+
/// The application shell: theme projection + router. Nothing else lives here —
|
|
8
|
+
/// features live under `ui/<feature>/`, data access under `data/`.
|
|
9
|
+
class App extends ConsumerWidget {
|
|
10
|
+
const App({super.key});
|
|
11
|
+
|
|
12
|
+
@override
|
|
13
|
+
Widget build(BuildContext context, WidgetRef ref) {
|
|
14
|
+
return MaterialApp.router(
|
|
15
|
+
title: '<%= name %>',
|
|
16
|
+
routerConfig: ref.watch(routerProvider),
|
|
17
|
+
// Both themes are built from the design system's projected brand tokens.
|
|
18
|
+
// Dual-theme support is a brand commitment, not an option.
|
|
19
|
+
theme: buildLightTheme(),
|
|
20
|
+
darkTheme: buildDarkTheme(),
|
|
21
|
+
themeMode: ThemeMode.system,
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/// Build-time configuration. Values arrive via --dart-define so no
|
|
2
|
+
/// environment file ships inside the binary.
|
|
3
|
+
abstract final class AppConfig {
|
|
4
|
+
/// Base URL of the workspace gateway this surface is wired to.
|
|
5
|
+
///
|
|
6
|
+
/// Override per environment:
|
|
7
|
+
/// flutter run --dart-define=API_BASE_URL=http://10.0.2.2:4000
|
|
8
|
+
///
|
|
9
|
+
/// Note: the Android emulator reaches the host machine's localhost at
|
|
10
|
+
/// 10.0.2.2; the iOS simulator uses localhost directly.
|
|
11
|
+
static const String apiBaseUrl = String.fromEnvironment(
|
|
12
|
+
'API_BASE_URL',
|
|
13
|
+
defaultValue: 'http://localhost:4000',
|
|
14
|
+
);
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
2
|
+
|
|
3
|
+
import '../../domain/models/health_status.dart';
|
|
4
|
+
import '../services/api_client.dart';
|
|
5
|
+
|
|
6
|
+
/// Repositories are the data layer's source of truth: they own caching,
|
|
7
|
+
/// retry, and the translation of contract payloads into domain models.
|
|
8
|
+
/// View models depend on this abstract class, so tests substitute an
|
|
9
|
+
/// in-memory fake without a mocking framework
|
|
10
|
+
/// (docs/principles/stack/flutter/architecture.md).
|
|
11
|
+
abstract class StatusRepository {
|
|
12
|
+
Future<HealthStatus> status();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/// The remote implementation consumes the typed client. Nothing above this
|
|
16
|
+
/// layer knows the transport.
|
|
17
|
+
class RemoteStatusRepository implements StatusRepository {
|
|
18
|
+
RemoteStatusRepository(this._client);
|
|
19
|
+
|
|
20
|
+
final ApiClient _client;
|
|
21
|
+
|
|
22
|
+
@override
|
|
23
|
+
Future<HealthStatus> status() async {
|
|
24
|
+
try {
|
|
25
|
+
return await _client.health();
|
|
26
|
+
} catch (_) {
|
|
27
|
+
// An unreachable gateway is a state the UI renders, not an exception
|
|
28
|
+
// the view model unwinds on.
|
|
29
|
+
return const HealthStatus.unreachable();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
final statusRepositoryProvider = Provider<StatusRepository>(
|
|
35
|
+
(ref) => RemoteStatusRepository(ref.watch(apiClientProvider)),
|
|
36
|
+
);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import 'package:dio/dio.dart';
|
|
2
|
+
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
|
+
|
|
4
|
+
import '../../config/app_config.dart';
|
|
5
|
+
import '../../domain/models/health_status.dart';
|
|
6
|
+
|
|
7
|
+
/// The core-access seam: a thin, typed dio client bound to the workspace
|
|
8
|
+
/// gateway (docs/principles/stack/flutter/architecture.md).
|
|
9
|
+
///
|
|
10
|
+
/// Contract-client tooling stance (O8): this client is hand-rolled and stays
|
|
11
|
+
/// deliberately thin — one method per promoted-contract operation, typed
|
|
12
|
+
/// request/response models in domain/models. That is the lightest path while
|
|
13
|
+
/// the contract surface is small, and it adds no JVM codegen dependency to the
|
|
14
|
+
/// toolchain. When the promoted openapi.yaml grows past a handful of
|
|
15
|
+
/// operations, switch to generated clients via openapi_generator's dart-dio
|
|
16
|
+
/// output (build_runner) and keep this class as the seam the repositories
|
|
17
|
+
/// consume — nothing above the data layer changes.
|
|
18
|
+
class ApiClient {
|
|
19
|
+
ApiClient(this._dio);
|
|
20
|
+
|
|
21
|
+
final Dio _dio;
|
|
22
|
+
|
|
23
|
+
/// Probe the gateway's health endpoint — the wiring proof the home feature
|
|
24
|
+
/// renders. Replace and extend with the operations your promoted contract
|
|
25
|
+
/// defines.
|
|
26
|
+
///
|
|
27
|
+
/// `/health` is what GroundWork's Go and Python cores serve. If this
|
|
28
|
+
/// surface fronts a Next.js BFF instead, its route is `/api/healthz` —
|
|
29
|
+
/// adjust the path to your gateway, not the other way around.
|
|
30
|
+
Future<HealthStatus> health() async {
|
|
31
|
+
final response = await _dio.get<Map<String, dynamic>>('/health');
|
|
32
|
+
return HealthStatus.fromJson(response.data ?? const <String, dynamic>{});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/// The auth seam: an async token supplier the request interceptor consults on
|
|
37
|
+
/// every call. The default is unauthenticated — wire your identity provider
|
|
38
|
+
/// (e.g. the Clerk session JWT on a Clerk-protected core) by overriding this
|
|
39
|
+
/// provider; the core's `/health` route stays public either way.
|
|
40
|
+
final authTokenProvider = Provider<Future<String?> Function()>(
|
|
41
|
+
(ref) => () async => null,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
/// Builds the Authorization interceptor from a token supplier. Kept as a
|
|
45
|
+
/// top-level function so tests exercise it without booting a widget tree.
|
|
46
|
+
Interceptor authInterceptor(Future<String?> Function() token) {
|
|
47
|
+
return InterceptorsWrapper(
|
|
48
|
+
onRequest: (options, handler) async {
|
|
49
|
+
final value = await token();
|
|
50
|
+
if (value != null && value.isNotEmpty) {
|
|
51
|
+
options.headers['Authorization'] = 'Bearer $value';
|
|
52
|
+
}
|
|
53
|
+
handler.next(options);
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/// The client is a provider like every other shared dependency, so tests
|
|
59
|
+
/// override it (or the repositories above it) with fakes.
|
|
60
|
+
final apiClientProvider = Provider<ApiClient>((ref) {
|
|
61
|
+
final dio = Dio(
|
|
62
|
+
BaseOptions(
|
|
63
|
+
baseUrl: AppConfig.apiBaseUrl,
|
|
64
|
+
connectTimeout: const Duration(seconds: 5),
|
|
65
|
+
receiveTimeout: const Duration(seconds: 10),
|
|
66
|
+
headers: const {'Accept': 'application/json'},
|
|
67
|
+
),
|
|
68
|
+
);
|
|
69
|
+
dio.interceptors.add(authInterceptor(ref.read(authTokenProvider)));
|
|
70
|
+
return ApiClient(dio);
|
|
71
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/// The gateway's health, as the home feature renders it.
|
|
2
|
+
///
|
|
3
|
+
/// Domain models are immutable. This one is a plain const class because it is
|
|
4
|
+
/// trivial; once models carry real shape (unions, copyWith, JSON round-trips),
|
|
5
|
+
/// introduce freezed — it earns its place at that point, not before
|
|
6
|
+
/// (docs/principles/stack/flutter/architecture.md).
|
|
7
|
+
class HealthStatus {
|
|
8
|
+
const HealthStatus({required this.reachable, this.status = ''});
|
|
9
|
+
|
|
10
|
+
factory HealthStatus.fromJson(Map<String, dynamic> json) {
|
|
11
|
+
return HealthStatus(
|
|
12
|
+
reachable: true,
|
|
13
|
+
status: json['status']?.toString() ?? 'ok',
|
|
14
|
+
);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const HealthStatus.unreachable()
|
|
18
|
+
: reachable = false,
|
|
19
|
+
status = 'unreachable';
|
|
20
|
+
|
|
21
|
+
final bool reachable;
|
|
22
|
+
final String status;
|
|
23
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import 'package:flutter/material.dart';
|
|
2
|
+
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
3
|
+
|
|
4
|
+
import 'app.dart';
|
|
5
|
+
|
|
6
|
+
void main() {
|
|
7
|
+
// ProviderScope is the root of the provider graph — state management and
|
|
8
|
+
// dependency injection in one mechanism. Everything shared is a provider;
|
|
9
|
+
// see docs/principles/stack/flutter/state-management.md.
|
|
10
|
+
runApp(const ProviderScope(child: App()));
|
|
11
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|
2
|
+
import 'package:go_router/go_router.dart';
|
|
3
|
+
|
|
4
|
+
import 'ui/home/home_view.dart';
|
|
5
|
+
|
|
6
|
+
/// The route table. go_router makes every declared route deep-linkable, and
|
|
7
|
+
/// the URL is a first-class state container — state the route already encodes
|
|
8
|
+
/// is never duplicated in a provider.
|
|
9
|
+
///
|
|
10
|
+
/// As the table grows: adopt go_router_builder for compile-checked typed
|
|
11
|
+
/// routes, StatefulShellRoute for tab scaffolds, and a centralized `redirect`
|
|
12
|
+
/// for auth guards. See docs/principles/stack/flutter/widgets-and-composition.md.
|
|
13
|
+
final routerProvider = Provider<GoRouter>((ref) {
|
|
14
|
+
return GoRouter(
|
|
15
|
+
routes: [
|
|
16
|
+
GoRoute(
|
|
17
|
+
path: '/',
|
|
18
|
+
name: 'home',
|
|
19
|
+
builder: (context, state) => const HomeView(),
|
|
20
|
+
),
|
|
21
|
+
],
|
|
22
|
+
);
|
|
23
|
+
});
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import 'package:flutter/material.dart';
|
|
2
|
+
|
|
3
|
+
import 'brand_palette.dart';
|
|
4
|
+
|
|
5
|
+
/// Builds ThemeData from the generated BrandPalette projection.
|
|
6
|
+
///
|
|
7
|
+
/// Widgets consume Theme.of(context) and the [StatusColors] extension — never
|
|
8
|
+
/// BrandPalette directly, and never Color(0xFF...) literals. A hex literal in
|
|
9
|
+
/// a widget file is a review finding
|
|
10
|
+
/// (docs/principles/stack/flutter/widgets-and-composition.md).
|
|
11
|
+
ThemeData buildLightTheme() => _buildTheme(Brightness.light);
|
|
12
|
+
|
|
13
|
+
ThemeData buildDarkTheme() => _buildTheme(Brightness.dark);
|
|
14
|
+
|
|
15
|
+
ThemeData _buildTheme(Brightness brightness) {
|
|
16
|
+
final bool dark = brightness == Brightness.dark;
|
|
17
|
+
|
|
18
|
+
final ColorScheme scheme = ColorScheme.fromSeed(
|
|
19
|
+
seedColor: dark ? BrandPalette.primaryDark : BrandPalette.primaryLight,
|
|
20
|
+
brightness: brightness,
|
|
21
|
+
).copyWith(
|
|
22
|
+
primary: dark ? BrandPalette.primaryDark : BrandPalette.primaryLight,
|
|
23
|
+
secondary: dark ? BrandPalette.accentDark : BrandPalette.accentLight,
|
|
24
|
+
surface: dark ? BrandPalette.surfaceDark : BrandPalette.surfaceLight,
|
|
25
|
+
surfaceContainerHighest:
|
|
26
|
+
dark ? BrandPalette.surfaceAltDark : BrandPalette.surfaceAltLight,
|
|
27
|
+
onSurface: dark ? BrandPalette.textBodyDark : BrandPalette.textBodyLight,
|
|
28
|
+
error: dark ? BrandPalette.errorDark : BrandPalette.errorLight,
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
final BorderRadius radius = BorderRadius.circular(BrandPalette.radiusBase);
|
|
32
|
+
|
|
33
|
+
final ThemeData base = ThemeData(
|
|
34
|
+
useMaterial3: true,
|
|
35
|
+
colorScheme: scheme,
|
|
36
|
+
scaffoldBackgroundColor: scheme.surface,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
return base.copyWith(
|
|
40
|
+
textTheme: base.textTheme
|
|
41
|
+
.apply(fontFamily: BrandPalette.bodyFontFamily)
|
|
42
|
+
.copyWith(
|
|
43
|
+
headlineLarge: base.textTheme.headlineLarge?.copyWith(
|
|
44
|
+
fontFamily: BrandPalette.displayFontFamily,
|
|
45
|
+
fontWeight: FontWeight.values[
|
|
46
|
+
(BrandPalette.displayFontWeight ~/ 100 - 1).clamp(0, 8)],
|
|
47
|
+
),
|
|
48
|
+
headlineMedium: base.textTheme.headlineMedium?.copyWith(
|
|
49
|
+
fontFamily: BrandPalette.displayFontFamily,
|
|
50
|
+
fontWeight: FontWeight.values[
|
|
51
|
+
(BrandPalette.displayFontWeight ~/ 100 - 1).clamp(0, 8)],
|
|
52
|
+
),
|
|
53
|
+
titleLarge: base.textTheme.titleLarge?.copyWith(
|
|
54
|
+
fontFamily: BrandPalette.displayFontFamily,
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
cardTheme: base.cardTheme.copyWith(
|
|
58
|
+
shape: RoundedRectangleBorder(borderRadius: radius),
|
|
59
|
+
),
|
|
60
|
+
filledButtonTheme: FilledButtonThemeData(
|
|
61
|
+
style: FilledButton.styleFrom(
|
|
62
|
+
shape: RoundedRectangleBorder(borderRadius: radius),
|
|
63
|
+
),
|
|
64
|
+
),
|
|
65
|
+
inputDecorationTheme: InputDecorationTheme(
|
|
66
|
+
border: OutlineInputBorder(borderRadius: radius),
|
|
67
|
+
),
|
|
68
|
+
extensions: <ThemeExtension<dynamic>>[
|
|
69
|
+
StatusColors(
|
|
70
|
+
success: dark ? BrandPalette.successDark : BrandPalette.successLight,
|
|
71
|
+
warning: dark ? BrandPalette.warningDark : BrandPalette.warningLight,
|
|
72
|
+
info: dark ? BrandPalette.infoDark : BrandPalette.infoLight,
|
|
73
|
+
),
|
|
74
|
+
],
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/// Semantic status colours the Material ColorScheme has no roles for.
|
|
79
|
+
/// Read via `Theme.of(context).extension<StatusColors>()!`.
|
|
80
|
+
@immutable
|
|
81
|
+
class StatusColors extends ThemeExtension<StatusColors> {
|
|
82
|
+
const StatusColors({
|
|
83
|
+
required this.success,
|
|
84
|
+
required this.warning,
|
|
85
|
+
required this.info,
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
final Color success;
|
|
89
|
+
final Color warning;
|
|
90
|
+
final Color info;
|
|
91
|
+
|
|
92
|
+
@override
|
|
93
|
+
StatusColors copyWith({Color? success, Color? warning, Color? info}) {
|
|
94
|
+
return StatusColors(
|
|
95
|
+
success: success ?? this.success,
|
|
96
|
+
warning: warning ?? this.warning,
|
|
97
|
+
info: info ?? this.info,
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
@override
|
|
102
|
+
StatusColors lerp(StatusColors? other, double t) {
|
|
103
|
+
if (other == null) return this;
|
|
104
|
+
return StatusColors(
|
|
105
|
+
success: Color.lerp(success, other.success, t)!,
|
|
106
|
+
warning: Color.lerp(warning, other.warning, t)!,
|
|
107
|
+
info: Color.lerp(info, other.info, t)!,
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
}
|