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,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: groundwork-electron-engineer
|
|
3
|
+
description: >
|
|
4
|
+
Implement, review, and refactor Electron desktop applications using the
|
|
5
|
+
hardened main/preload/renderer process model, typed IPC contracts with
|
|
6
|
+
runtime validation, enforced security defaults, fuse-hardened Forge
|
|
7
|
+
packaging, and Playwright _electron boot smokes. Use for work touching the
|
|
8
|
+
main process, preload bridges, IPC channels, BrowserWindow configuration,
|
|
9
|
+
contextBridge, utilityProcess, auto-update, code signing, desktop packaging,
|
|
10
|
+
nativeTheme, or Electron testing. Make sure to use this skill whenever a
|
|
11
|
+
user is working in an Electron codebase, building desktop shell features,
|
|
12
|
+
fixing desktop app bugs, or reviewing Electron code.
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# Electron Engineer
|
|
16
|
+
|
|
17
|
+
Desktop execution engineer for Electron applications. This skill guides implementation within the flagship-app architecture — a privileged main process that only orchestrates, fully sandboxed Node-free renderers behind a narrow typed bridge, security defaults that are baked rather than advisory, and a boot smoke driven by Playwright's `_electron` driver, the agent-closable loop this stack was chosen for.
|
|
18
|
+
|
|
19
|
+
## Operating Contract
|
|
20
|
+
|
|
21
|
+
1. Locate the process before editing. Main, preload, renderer, and shared each have distinct responsibilities and their own compiler context; a change that blurs the boundary is wrong even when it works.
|
|
22
|
+
2. The capability core owns business logic. The renderer is a thin surface adapter, and privileged core access belongs on main's side of the IPC seam — never re-implement a rule the core's contract already proves.
|
|
23
|
+
3. Route durable desktop policy to the canonical docs (`docs/principles/stack/electron/`) instead of duplicating it in code comments or this skill.
|
|
24
|
+
4. Verify typecheck (both tsconfigs), lint (including the boundary rules), unit tests, and — for shell-touching changes — the boot smoke before declaring work complete.
|
|
25
|
+
|
|
26
|
+
## Code intelligence (repo map + Serena)
|
|
27
|
+
|
|
28
|
+
GroundWork gives you a deterministic **repo map** (`npx groundwork-method repo-map` — tree-sitter import edges + PageRank centrality, cached to `.groundwork/cache/repo-map.json`) and the **Serena** MCP server (LSP-backed symbol navigation and editing), registered at init. Orient before reading widely: refresh the map, read its `centrality` ranking to find the hubs, then use Serena to navigate them (`get_symbols_overview` / `find_symbol` / `find_referencing_symbols`) and make reference-aware edits (`replace_symbol_body` / `rename`). Full workflow and the graceful-degradation contract live in `.groundwork/skills/code-intelligence.md`; fall back to ordinary reads and edits when they are unavailable.
|
|
29
|
+
|
|
30
|
+
## Core Pillars
|
|
31
|
+
|
|
32
|
+
1. **Main Is an Orchestrator** — Window creation, security policy, IPC registration, OS integration. CPU-heavy or crash-prone work runs in a `utilityProcess` with MessagePorts wired renderer↔utility directly. A blocked main process freezes every window the app has.
|
|
33
|
+
|
|
34
|
+
2. **The Renderer Is a Web App** — Sandboxed, context-isolated, Node-free; its only platform surface is the preload-exposed `window.api`. Everything it shares with the web stack — component idiom, styling, accessibility — follows the web rules unchanged (see the deferrals below).
|
|
35
|
+
|
|
36
|
+
3. **IPC Is a Contract Boundary** — One shared channel-map type consumed by both sides; `invoke`/`handle` for two-way; sender validation in every handler and zod validation for non-trivial payloads. The seam gets the same discipline the core enforces at its contracts.
|
|
37
|
+
|
|
38
|
+
4. **Security Defaults Are Baked** — The hardened quartet, denied-by-default permissions, restricted navigation, allowlisted `openExternal`, custom-protocol content, strict CSP, and package-time fuses. None of these is a hardening backlog item; loosening one is a defect.
|
|
39
|
+
|
|
40
|
+
5. **The Smoke Closes the Loop** — Playwright `_electron` launches the real built app, drives its window as an ordinary Page, and evaluates in the main process — headless under xvfb in CI. Generate → boot → test → observe, no human in the loop.
|
|
41
|
+
|
|
42
|
+
## How to Use This Skill
|
|
43
|
+
|
|
44
|
+
Match the user's task to the smallest relevant reference set. Most tasks touch one or two references.
|
|
45
|
+
|
|
46
|
+
| Topic | Reference | Load When |
|
|
47
|
+
|-------|-----------|-----------|
|
|
48
|
+
| Process Model | `references/process-model.md` | Placing new code, main vs preload vs renderer vs shared, utilityProcess, the enforced folder boundary. |
|
|
49
|
+
| IPC Contracts | `references/ipc-contracts.md` | Adding or changing channels, the bridge, validation at the seam, TanStack Query over IPC, push events. |
|
|
50
|
+
| Security | `references/security.md` | BrowserWindow options, permissions, navigation, openExternal, CSP, the custom protocol, fuses, Electron upgrades. |
|
|
51
|
+
| Packaging & Updates | `references/packaging-and-updates.md` | Forge config, makers, fuses at package time, code signing, notarization, auto-update routes. |
|
|
52
|
+
| Testing & Smoke | `references/testing-and-smoke.md` | The three test tiers, Playwright `_electron` patterns, xvfb CI, skip-with-reason guards. |
|
|
53
|
+
| Theming & Tokens | `references/theming-and-tokens.md` | The generated brand.css, Tailwind token mapping, nativeTheme sync, dark mode on desktop. |
|
|
54
|
+
|
|
55
|
+
## Shared with the web stack — deferrals
|
|
56
|
+
|
|
57
|
+
The renderer is a normal Vite + React web app, and the web stack's rules apply to it unchanged. That knowledge is owned by the Next.js engineer skill (`.agents/skills/groundwork-nextjs-engineer/`, installed alongside any web surface) and by `docs/principles/stack/typescript/frontend.md` (always deployed with this app); it is deliberately **not** duplicated here:
|
|
58
|
+
|
|
59
|
+
- **Component idiom, composition, and visual language** → `groundwork-nextjs-engineer/references/visual-language.md` and `groundwork-nextjs-engineer/references/ux-principles.md`. Skip the App Router / Server Component material — an Electron renderer is fully client-side and has no server boundary.
|
|
60
|
+
- **Tailwind usage and styling discipline** → `groundwork-nextjs-engineer/references/tailwind-and-styling.md`. Only the desktop delta (the generated token file, nativeTheme sync) lives in this skill's `references/theming-and-tokens.md`.
|
|
61
|
+
- **Data-fetching discipline** (cache-layer rules, no fetch-in-useEffect) → `groundwork-nextjs-engineer/references/data-fetching.md`. The transport here is the IPC bridge with TanStack Query instead of SWR over HTTP — that delta is in `references/ipc-contracts.md`.
|
|
62
|
+
- **Accessibility** → `groundwork-nextjs-engineer/references/ux-principles.md` (Accessibility) and `groundwork-nextjs-engineer/references/testing.md` (Accessibility Testing). Desktop changes nothing about it.
|
|
63
|
+
- **Component testing idiom** (Testing Library patterns, what to assert) → `groundwork-nextjs-engineer/references/testing.md`. This skill's testing reference covers only what the shell adds: the process-split test projects and the `_electron` smoke.
|
|
64
|
+
|
|
65
|
+
When the workspace has no web surface, the same canon is available as `docs/principles/stack/typescript/frontend.md` in the project's deployed docs.
|
|
66
|
+
|
|
67
|
+
## Task Routing
|
|
68
|
+
|
|
69
|
+
- **New capability reaching the shell** → Load `references/ipc-contracts.md`. Contract type first, then handler (validated), then bridge method, then the renderer query.
|
|
70
|
+
- **New window / shell behaviour** → Load `references/process-model.md` and `references/security.md`. The quartet and the policy handlers apply to every window, no exceptions.
|
|
71
|
+
- **Heavy work (parsing, crypto, indexing)** → Load `references/process-model.md`. It goes in a `utilityProcess`, not main.
|
|
72
|
+
- **UI/visual work** → Load `references/theming-and-tokens.md`, then defer to the web stack's styling references. Check the generated token file before adding any colour.
|
|
73
|
+
- **Release/packaging work** → Load `references/packaging-and-updates.md`. Fuses and signing live in the pipeline; signing material never enters the repo.
|
|
74
|
+
- **Test work** → Load `references/testing-and-smoke.md`. Pick the cheapest tier that can carry the assertion; the smoke stays thin.
|
|
75
|
+
- **Electron upgrade** → Load `references/security.md` (currency window). Treat a skipped support window as a security finding.
|
|
76
|
+
|
|
77
|
+
## Safety Gates
|
|
78
|
+
|
|
79
|
+
- Do not loosen the hardened quartet — `contextIsolation: true`, `sandbox: true`, `nodeIntegration: false`, `webSecurity: true` — for any window, flag, or debugging session.
|
|
80
|
+
- Do not expose `ipcRenderer`, any Electron module, or a generic `invoke` passthrough on `window`; the bridge stays narrow and purpose-named.
|
|
81
|
+
- Do not add an IPC handler without sender validation, or accept a non-trivial payload without zod parsing.
|
|
82
|
+
- Do not import Electron or Node built-ins in `src/renderer/` or `src/shared/` — the lint boundary and per-process tsconfigs enforce this; a suppression comment is a review finding.
|
|
83
|
+
- Do not serve app content over `file://` or weaken the CSP to unblock a feature.
|
|
84
|
+
- Do not ship a build whose fuses were not flipped by the packaging pipeline, and do not flip `nodeCliInspect` off — it breaks the Playwright `_electron` loop.
|
|
85
|
+
- Run typecheck, lint, and unit tests where the toolchain is available; report a tier as skipped-with-reason (never silently green) where it is not.
|
|
86
|
+
|
|
87
|
+
## Hallucination Controls
|
|
88
|
+
|
|
89
|
+
Before presenting Electron guidance as factual:
|
|
90
|
+
|
|
91
|
+
- Check `package.json` for the actual Electron major and available dependencies; the support window moves every 8 weeks.
|
|
92
|
+
- Check `src/shared/ipc.ts` for the real channel map before referencing or inventing channels.
|
|
93
|
+
- Check `src/main/policy.ts` for the actual navigation/permission/external-URL rules before describing the app's security behaviour.
|
|
94
|
+
- Check `electron.vite.config.ts` and `forge.config.ts` for the real build/packaging shape before recommending tooling changes.
|
|
95
|
+
- Label any recommendation based on general Electron knowledge (rather than project-specific patterns) as an inference.
|
|
96
|
+
|
|
97
|
+
## Output Expectations
|
|
98
|
+
|
|
99
|
+
- Changes name the process each touched file runs in and why the code belongs there.
|
|
100
|
+
- IPC changes show all four pieces: contract type, validated handler, bridge method, renderer consumption.
|
|
101
|
+
- Shell changes state their security impact explicitly, even when it is "none".
|
|
102
|
+
- Verification steps name the specific Nx targets (`typecheck`, `lint`, `test`, `smoke`) with the skipped-with-reason caveat where the binary or display is absent.
|
|
103
|
+
- Recommendations distinguish project conventions from general Electron practice.
|
|
104
|
+
|
|
105
|
+
## Antipatterns
|
|
106
|
+
|
|
107
|
+
Reject these patterns:
|
|
108
|
+
|
|
109
|
+
- **Node-enabled renderers** — `nodeIntegration: true` also silently kills the sandbox for that renderer; the controls fail as a set.
|
|
110
|
+
- **Raw ipcRenderer on window** — The bridge exists to be narrow; this makes it infinitely wide.
|
|
111
|
+
- **`sendSync`** — Blocks the renderer event loop. There is always an async shape.
|
|
112
|
+
- **Untyped ad-hoc channels** — A channel missing from the shared contract is a seam that drifts silently.
|
|
113
|
+
- **Trusting renderer input in main** — Compile-time types are not runtime guarantees; validate sender and payload.
|
|
114
|
+
- **CPU-heavy work in main** — It freezes every window. `utilityProcess` exists.
|
|
115
|
+
- **Shared folders with runtime code** — `src/shared/` carries types only; shared behaviour leaks Node toward the sandbox.
|
|
116
|
+
- **`webSecurity: false` or CSP wildcards to "unblock" development** — Fix the content, not the boundary.
|
|
117
|
+
- **Un-fused release builds** — Post-CVE-2025-55305, ASAR integrity off is a shipping defect.
|
|
118
|
+
- **Fat smoke suites** — The smoke proves boot and wiring; rules are proven in unit tiers and at the core's contract.
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# IPC Contracts
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [The Seam Is a Contract](#the-seam-is-a-contract)
|
|
5
|
+
- [Adding a Channel End-to-End](#adding-a-channel-end-to-end)
|
|
6
|
+
- [Validation at the Trust Boundary](#validation-at-the-trust-boundary)
|
|
7
|
+
- [Push Channels (Main → Renderer)](#push-channels-main--renderer)
|
|
8
|
+
- [TanStack Query Over the Bridge](#tanstack-query-over-the-bridge)
|
|
9
|
+
- [Core Access for a Hosted Capability Core](#core-access-for-a-hosted-capability-core)
|
|
10
|
+
- [The electron-trpc Variant](#the-electron-trpc-variant)
|
|
11
|
+
- [Anti-Patterns](#anti-patterns)
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## The Seam Is a Contract
|
|
16
|
+
|
|
17
|
+
The main↔renderer seam gets the same discipline the capability core enforces at its contracts. One module — `src/shared/ipc.ts` — declares every channel; both sides import it; a rename or payload change is a compile error in both processes.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
// src/shared/ipc.ts (types only)
|
|
21
|
+
export type IpcContract = {
|
|
22
|
+
'app:get-status': { args: []; result: AppStatus };
|
|
23
|
+
'shell:open-external': { args: [url: string]; result: OpenExternalResult };
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Channel naming: `domain:verb` (`project:open`, `settings:get`, `theme:changed`). The bridge methods name **capabilities** (`getStatus`, `openExternal`), never transport (`invoke`, `send`).
|
|
28
|
+
|
|
29
|
+
`invoke`/`handle` is the two-way pattern — promise-based, errors propagate to the caller. `send`/`on` carries one-way pushes from main. `sendSync` is forbidden: it blocks the renderer event loop for the round trip.
|
|
30
|
+
|
|
31
|
+
## Adding a Channel End-to-End
|
|
32
|
+
|
|
33
|
+
Four pieces, in this order. A channel missing any of them is incomplete.
|
|
34
|
+
|
|
35
|
+
**1. Contract type** (`src/shared/ipc.ts`):
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
export type ProjectSummary = { path: string; fileCount: number };
|
|
39
|
+
|
|
40
|
+
export type IpcContract = {
|
|
41
|
+
// ...existing channels
|
|
42
|
+
'project:open': { args: [path: string]; result: ProjectSummary };
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
export type RendererApi = {
|
|
46
|
+
// ...existing methods
|
|
47
|
+
openProject: (path: string) => Promise<ProjectSummary>;
|
|
48
|
+
};
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**2. Validated handler** (`src/main/ipc.ts`):
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const openProjectPayload = z.string().min(1);
|
|
55
|
+
|
|
56
|
+
ipcMain.handle('project:open', async (event, rawPath: unknown): Promise<ProjectSummary> => {
|
|
57
|
+
assertTrustedSender(event, devServerUrl); // every handler
|
|
58
|
+
const projectPath = openProjectPayload.parse(rawPath); // non-trivial payloads
|
|
59
|
+
return openProject(projectPath); // delegate; main orchestrates
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**3. Bridge method** (`src/preload/index.ts`):
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const api: RendererApi = {
|
|
67
|
+
// ...existing methods
|
|
68
|
+
openProject: (path) => ipcRenderer.invoke('project:open', path),
|
|
69
|
+
};
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
**4. Renderer consumption** — through the cache layer, never a bare effect:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const { data } = useQuery({
|
|
76
|
+
queryKey: ['project', path],
|
|
77
|
+
queryFn: () => window.api.openProject(path),
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Typing keeps the pieces honest: `RendererApi` is implemented by preload and consumed via the `Window` augmentation in `src/renderer/src/env.d.ts`, so a drifted signature fails both tsconfigs.
|
|
82
|
+
|
|
83
|
+
## Validation at the Trust Boundary
|
|
84
|
+
|
|
85
|
+
Main treats renderer input as untrusted, the same way an API treats the public internet. Two checks in every handler:
|
|
86
|
+
|
|
87
|
+
- **Sender validation, always.** `assertTrustedSender` verifies `event.senderFrame.url` against the bundle protocol / dev-server origin (security checklist item 17). A destroyed or missing frame is rejected. This is what stops an iframe or a navigated-away window from driving privileged code.
|
|
88
|
+
- **Payload validation with zod for anything beyond a trivial getter.** TypeScript types vanish at runtime; a compromised renderer is not bound by them. `z.string().url()`, `z.object({...}).strict()` — parse, don't trust. A handler taking no arguments (like `app:get-status`) needs only the sender check.
|
|
89
|
+
|
|
90
|
+
Failures throw — `invoke` rejects in the renderer, which is correct: a rejected privileged call is a bug or an attack, not a state to paper over.
|
|
91
|
+
|
|
92
|
+
## Push Channels (Main → Renderer)
|
|
93
|
+
|
|
94
|
+
One-way events (theme changes, update progress, file-watcher hits) flow as `webContents.send` from main to a **subscription method on the bridge** that returns an unsubscribe function:
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// preload
|
|
98
|
+
onThemeChanged: (callback) => {
|
|
99
|
+
const listener = (_e: Electron.IpcRendererEvent, theme: ThemeInfo) => callback(theme);
|
|
100
|
+
ipcRenderer.on('theme:changed', listener);
|
|
101
|
+
return () => ipcRenderer.removeListener('theme:changed', listener);
|
|
102
|
+
},
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Declare push channels in `IpcPushContract` so they are part of the contract too. The renderer never receives the event object — only the typed payload. Theme is the canonical example: `nativeTheme` in main, broadcast on `updated`, mirrored onto `<html data-theme>` (`references/theming-and-tokens.md`).
|
|
106
|
+
|
|
107
|
+
## TanStack Query Over the Bridge
|
|
108
|
+
|
|
109
|
+
The renderer's data source is IPC, not HTTP, and TanStack Query is the convergent IPC-aware pattern: `queryFn`s call the typed bridge; caching, retry, and invalidation work exactly as in an HTTP app. This is the desktop shell's one deviation from the web stack's SWR pick — the one-cache-one-mental-model rule still holds: **TanStack Query is the renderer's only query library.**
|
|
110
|
+
|
|
111
|
+
Push events invalidate queries through a bridge subscription:
|
|
112
|
+
|
|
113
|
+
```ts
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
return window.api.onProjectChanged(() => {
|
|
116
|
+
void queryClient.invalidateQueries({ queryKey: ['project'] });
|
|
117
|
+
});
|
|
118
|
+
}, [queryClient]);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
(The effect here manages a subscription — that is its legitimate use. *Fetching* in an effect is still wrong; see the web stack's data-fetching reference for the full discipline.)
|
|
122
|
+
|
|
123
|
+
## Core Access for a Hosted Capability Core
|
|
124
|
+
|
|
125
|
+
When the workspace has a hosted core (services behind promoted contracts), the desktop app reaches it from **main's side of the seam**: main holds the HTTP client, tokens, and retries; the renderer asks main over IPC. This keeps credentials out of the sandboxed process, keeps the strict CSP intact (`default-src 'self'` — the renderer fetches nothing), and gives core calls the same sender/payload validation as every other channel. Do not punch `connect-src` holes in the CSP to let the renderer fetch the gateway directly.
|
|
126
|
+
|
|
127
|
+
## The electron-trpc Variant
|
|
128
|
+
|
|
129
|
+
tRPC-over-IPC (Zod inputs, queries/mutations/subscriptions, React Query integration) is the packaged version of this pattern — and a **recorded choice, not the default**: it sits in a maintenance lull (tRPC v11 support lives in forks) and adds per-call overhead on hot paths. The hand-rolled contract above covers the same ground with no dependency risk. Adopt electron-trpc only via a decision record naming what outgrew the hand-rolled seam.
|
|
130
|
+
|
|
131
|
+
## Anti-Patterns
|
|
132
|
+
|
|
133
|
+
- **Exposing `ipcRenderer`, a whole Electron module, or a generic `invoke(channel, ...args)` passthrough on `window`.** All three make the narrow bridge infinitely wide.
|
|
134
|
+
- **`sendSync`.** Always an async shape instead.
|
|
135
|
+
- **String-typed ad-hoc channels** with no entry in the shared contract.
|
|
136
|
+
- **Trusting renderer payloads or senders** because "the types guarantee it" — they don't, at runtime.
|
|
137
|
+
- **The `remote` module** or packages emulating it.
|
|
138
|
+
- **Raw `useEffect` IPC fetching.** Data goes through TanStack Query; effects only manage subscriptions.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Packaging & Updates
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [The Toolchain Split](#the-toolchain-split)
|
|
5
|
+
- [Anatomy of forge.config.ts](#anatomy-of-forgeconfigts)
|
|
6
|
+
- [Makers](#makers)
|
|
7
|
+
- [Code Signing](#code-signing)
|
|
8
|
+
- [Auto-Update Routes](#auto-update-routes)
|
|
9
|
+
- [Update Discipline](#update-discipline)
|
|
10
|
+
- [Version Hygiene](#version-hygiene)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## The Toolchain Split
|
|
15
|
+
|
|
16
|
+
Two tools, one pipeline:
|
|
17
|
+
|
|
18
|
+
- **electron-vite builds.** One `electron.vite.config.ts` with `main`/`preload`/`renderer` sections → `out/`. Renderer HMR and main/preload hot-reload in dev; `utilityProcess` workers via `?modulePath`. Tailwind loads as a Vite plugin in the **renderer section only**.
|
|
19
|
+
- **Electron Forge packages.** `forge.config.ts` drives `@electron/packager`, the makers, signing hooks, and `@electron/fuses` — the officially recommended pipeline, maintained in the `electron/` org.
|
|
20
|
+
|
|
21
|
+
`package.json` `main` points at `out/main/index.js`, so packaging always consumes the built output; the `package` Nx target runs the build first. Forge's own Vite plugin remains experimental and lags Vite majors — keep the electron-vite + Forge pairing. **electron-builder** is the recorded escape hatch when packaging needs outgrow Forge's makers (exotic targets, NSIS specifics, staged-rollout updater); switching to it is a decision record, not a preference.
|
|
22
|
+
|
|
23
|
+
## Anatomy of forge.config.ts
|
|
24
|
+
|
|
25
|
+
The generated config has three load-bearing parts:
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
packagerConfig: {
|
|
29
|
+
asar: true, // required for the integrity fuses to mean anything
|
|
30
|
+
appBundleId: '<org>.<app>', // macOS bundle id; pairs with the AppUserModelID main sets
|
|
31
|
+
},
|
|
32
|
+
makers: [new MakerZIP({}, ['darwin', 'linux', 'win32'])],
|
|
33
|
+
plugins: [new FusesPlugin({ ... })], // see references/security.md → Fuses
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
The fuses plugin is the part that must never be removed or moved out of the pipeline: it is what makes "an unhardened binary cannot ship" structurally true rather than procedurally hoped. `nodeCliInspect` stays on (Playwright `_electron` needs it); everything else is hardened per the table in `references/security.md`.
|
|
37
|
+
|
|
38
|
+
## Makers
|
|
39
|
+
|
|
40
|
+
ZIP is the scaffold's lowest-common-denominator maker — it packages on every host OS with no native tooling. Graduate per platform when distribution starts:
|
|
41
|
+
|
|
42
|
+
| Target | Maker | Notes |
|
|
43
|
+
|---|---|---|
|
|
44
|
+
| Windows installer | `@electron-forge/maker-squirrel` | Pairs with the Squirrel auto-update route; set `setupIcon`, match `appBundleId`/AppUserModelID |
|
|
45
|
+
| macOS disk image | `@electron-forge/maker-dmg` | Sign + notarize first or Gatekeeper rejects |
|
|
46
|
+
| Linux | `maker-deb` / `maker-rpm` | Needs `dpkg`/`rpm` on the build host |
|
|
47
|
+
|
|
48
|
+
Cross-platform makers generally require their native OS — package per-OS in CI matrix jobs, not on one machine.
|
|
49
|
+
|
|
50
|
+
## Code Signing
|
|
51
|
+
|
|
52
|
+
An unsigned build is a development artifact, never a release. Both platforms treat unsigned binaries as malware, because malware is what unsigned binaries usually are.
|
|
53
|
+
|
|
54
|
+
- **macOS:** Developer ID certificate + hardened runtime + entitlements, then notarization via `notarytool` (Forge wraps `@electron/notarize` — configure `osxSign`/`osxNotarize` in `packagerConfig`). `altool` is dead. Credentials arrive from CI secrets, never the repo.
|
|
55
|
+
- **Windows:** **Azure Artifact Signing** (renamed from Azure Trusted Signing; GA since Jan 2026) — cloud-HSM-backed, clears SmartScreen, runs from CI via signtool/jsign. USB-token OV/EV certificates cannot live in a pipeline; they are the legacy path. (Tooling note: post-rename CLI tools have needed `--prerelease` flags — verify current tool names when wiring CI.)
|
|
56
|
+
|
|
57
|
+
Signing config is wired in `forge.config.ts` when release credentials exist; until then the scaffold's unsigned `package` output is explicitly a dev artifact.
|
|
58
|
+
|
|
59
|
+
## Auto-Update Routes
|
|
60
|
+
|
|
61
|
+
Two sanctioned routes — pick by distribution model, record the choice:
|
|
62
|
+
|
|
63
|
+
1. **Open-source, GitHub-released:** `update-electron-app` (drop-in module) against **update.electronjs.org** — free, zero infrastructure, feeds the platform-native Squirrel updaters behind Electron's built-in `autoUpdater`. Serves only semver-tagged, non-draft releases.
|
|
64
|
+
2. **Everything else:** `electron-updater` with a generic/S3/GitHub feed — channels and staged rollouts included. Self-hosted feed servers only when rollout control demands them.
|
|
65
|
+
|
|
66
|
+
A hand-rolled update endpoint without semver and rollback discipline is an outage generator, not a third route.
|
|
67
|
+
|
|
68
|
+
## Update Discipline
|
|
69
|
+
|
|
70
|
+
Fixed rules, each one a classic self-inflicted outage when skipped:
|
|
71
|
+
|
|
72
|
+
- Never check for updates on `--squirrel-firstrun` — the install is still settling.
|
|
73
|
+
- Call `quitAndInstall()` only after the `update-downloaded` event.
|
|
74
|
+
- One in-flight `checkForUpdates()` at a time; double-calls corrupt state.
|
|
75
|
+
- `app.setAppUserModelId()` must match the Squirrel shortcut ID (the generated main sets it from the same `appId` as the bundle id) or Windows notifications detach.
|
|
76
|
+
- Staying inside the 3-major Electron support window is an update-discipline item (`references/security.md` → The Currency Window) — the auto-updater is the mechanism that makes the 8-week cadence shippable.
|
|
77
|
+
|
|
78
|
+
## Version Hygiene
|
|
79
|
+
|
|
80
|
+
- `version` in `package.json` is what `app.getVersion()` reports, what the smoke sees, and what update feeds compare — bump it semver-honestly per release.
|
|
81
|
+
- Pin the Electron major deliberately (`^42.0.0` floats within the major; that is correct — patch releases are Chromium security fixes).
|
|
82
|
+
- When bumping the Electron major, run the full tier set including the smoke in CI before merging: driver/runtime pairings occasionally regress (`references/security.md`).
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Process Model
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [The Three Processes](#the-three-processes)
|
|
5
|
+
- [Main Is an Orchestrator](#main-is-an-orchestrator)
|
|
6
|
+
- [The Enforced Folder Boundary](#the-enforced-folder-boundary)
|
|
7
|
+
- [Per-Process Compiler Contexts](#per-process-compiler-contexts)
|
|
8
|
+
- [utilityProcess for Heavy Work](#utilityprocess-for-heavy-work)
|
|
9
|
+
- [Shared Code Crosses as Types Only](#shared-code-crosses-as-types-only)
|
|
10
|
+
- [Adding a Window](#adding-a-window)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## The Three Processes
|
|
15
|
+
|
|
16
|
+
| Process | Runs | May import | Job |
|
|
17
|
+
|---|---|---|---|
|
|
18
|
+
| **main** (`src/main/`) | Node + Electron main APIs | anything | Orchestration: windows, security policy, IPC handlers, OS integration |
|
|
19
|
+
| **preload** (`src/preload/`) | sandboxed bridge context | `electron` (bridge subset) + shared types | Expose the narrow `window.api`; nothing else |
|
|
20
|
+
| **renderer** (`src/renderer/`) | Chromium, sandboxed, Node-free | web code + shared types | The UI — a normal Vite + React web app |
|
|
21
|
+
|
|
22
|
+
`src/shared/` is not a process: it is the contract-type module all three import (types only — see below).
|
|
23
|
+
|
|
24
|
+
This is the VS Code / Slack / Signal shape. It exists because a renderer with Node access turns any XSS into machine compromise, and a busy main process freezes every window at once.
|
|
25
|
+
|
|
26
|
+
## Main Is an Orchestrator
|
|
27
|
+
|
|
28
|
+
`src/main/index.ts` does four things: registers the bundle protocol, applies the security policy, registers IPC handlers, creates windows. Everything else is delegation.
|
|
29
|
+
|
|
30
|
+
The test for new main-process code: **can this take longer than a frame?** Parsing a large file, hashing, indexing, image work — yes, so it goes to a `utilityProcess`. Reading a config file, showing a dialog, registering a handler — no, main is fine.
|
|
31
|
+
|
|
32
|
+
Keep main's modules pure where possible: `src/main/policy.ts` holds the security rules with **no Electron imports**, which is why `policy.test.ts` runs in plain Node. When adding privileged logic, split it the same way — decision (pure module, unit-tested) from wiring (thin Electron glue in `index.ts`/`ipc.ts`).
|
|
33
|
+
|
|
34
|
+
## The Enforced Folder Boundary
|
|
35
|
+
|
|
36
|
+
```
|
|
37
|
+
src/
|
|
38
|
+
main/ # privileged orchestration
|
|
39
|
+
preload/ # the bridge — contextBridge only
|
|
40
|
+
renderer/ # the web app — no Node, no Electron
|
|
41
|
+
shared/ # IPC contract types — types only
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
The split is physical and lint-enforced (the Slack pattern): `eslint.config.mjs` carries `no-restricted-imports` blocks that fail the build when `src/renderer/` or `src/shared/` imports `electron` or a Node built-in. The rule exists because the boundary erodes one convenient import at a time, and each erosion is invisible until it is a sandbox hole.
|
|
45
|
+
|
|
46
|
+
Never suppress the rule. If the renderer "needs" a Node capability, that is a new IPC channel (`references/ipc-contracts.md`), not an exemption.
|
|
47
|
+
|
|
48
|
+
## Per-Process Compiler Contexts
|
|
49
|
+
|
|
50
|
+
Two tsconfigs police the boundary alongside the lint:
|
|
51
|
+
|
|
52
|
+
- `tsconfig.node.json` — main, preload, shared, configs, smoke tests. `types: ["node"]`, **no DOM lib**.
|
|
53
|
+
- `tsconfig.web.json` — renderer + shared. DOM lib, `jsx: react-jsx`, **no Node types**.
|
|
54
|
+
|
|
55
|
+
`npm run typecheck` (the `typecheck` Nx target) runs both. A renderer file that touches `process` or a main file that touches `document` is a compile error, not a code-review catch. When adding files, make sure they land in the right include set — a file checked by neither tsconfig is unverified code.
|
|
56
|
+
|
|
57
|
+
## utilityProcess for Heavy Work
|
|
58
|
+
|
|
59
|
+
`utilityProcess` is the documented home for CPU-intensive tasks, untrusted services, and crash-prone components — a `child_process.fork` equivalent launched through Chromium's Services API, with Node enabled and MessagePort support.
|
|
60
|
+
|
|
61
|
+
The pattern (VS Code's extension host is the reference):
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
// main: spawn and wire ports renderer↔utility DIRECTLY
|
|
65
|
+
import { utilityProcess, MessageChannelMain } from 'electron';
|
|
66
|
+
|
|
67
|
+
const worker = utilityProcess.fork(
|
|
68
|
+
new URL('./indexer.js?modulePath', import.meta.url).pathname,
|
|
69
|
+
);
|
|
70
|
+
const { port1, port2 } = new MessageChannelMain();
|
|
71
|
+
worker.postMessage({ type: 'port' }, [port1]);
|
|
72
|
+
window.webContents.postMessage('indexer:port', null, [port2]);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The direct port wiring matters: heavy traffic never transits — or blocks — main. electron-vite builds utility workers first-class via the `?modulePath` import suffix.
|
|
76
|
+
|
|
77
|
+
Use `utilityProcess`, not `child_process.fork`, for anything that talks to a renderer: fork has no port wiring and no Services API integration. Plugin-style or untrusted code never runs in the renderer — a utility process contains its crash or compromise.
|
|
78
|
+
|
|
79
|
+
## Shared Code Crosses as Types Only
|
|
80
|
+
|
|
81
|
+
`src/shared/ipc.ts` carries the channel map and payload types both sides import. It must contain **no runtime behaviour** — a "utils" module imported by main and renderer drags Node-flavoured code toward the sandbox and couples both sides' upgrade paths. The lint boundary enforces the import side; review enforces the no-runtime side: if a shared file gains a function body that does more than type-level work, move it.
|
|
82
|
+
|
|
83
|
+
Constants are the one nuance: a string-literal channel name in the contract type is fine; a shared object of behaviourful helpers is not.
|
|
84
|
+
|
|
85
|
+
## Adding a Window
|
|
86
|
+
|
|
87
|
+
Every window — main, settings, about, anything — gets the identical hardened construction:
|
|
88
|
+
|
|
89
|
+
1. Build it in `src/main/index.ts` (or a sibling module main imports) with the full `webPreferences` quartet and the shared preload.
|
|
90
|
+
2. Load content only from the bundle protocol or the dev server; never a remote URL, never `file://`.
|
|
91
|
+
3. The global policy (`applySecurityPolicy`) already covers it — permission denial and navigation restriction hook `web-contents-created`, so they apply to new windows automatically. Do not bypass that path with per-window overrides.
|
|
92
|
+
4. If the window needs new capabilities, they arrive as IPC channels, not as loosened `webPreferences`.
|
|
93
|
+
|
|
94
|
+
A second renderer entry point goes in `electron.vite.config.ts`'s renderer `rollupOptions.input` map, with its own HTML file carrying the same CSP.
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# Security
|
|
2
|
+
|
|
3
|
+
## Table of Contents
|
|
4
|
+
- [The Posture](#the-posture)
|
|
5
|
+
- [The Hardened Quartet](#the-hardened-quartet)
|
|
6
|
+
- [Permissions: Denied by Default](#permissions-denied-by-default)
|
|
7
|
+
- [Navigation and window.open](#navigation-and-windowopen)
|
|
8
|
+
- [shell.openExternal Allowlist](#shellopenexternal-allowlist)
|
|
9
|
+
- [The Custom Protocol](#the-custom-protocol)
|
|
10
|
+
- [Content-Security-Policy](#content-security-policy)
|
|
11
|
+
- [Fuses](#fuses)
|
|
12
|
+
- [The Currency Window](#the-currency-window)
|
|
13
|
+
- [Security Review Checklist](#security-review-checklist)
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## The Posture
|
|
18
|
+
|
|
19
|
+
An Electron app is a browser with a privileged process attached: every web vulnerability becomes a local-machine vulnerability the moment a boundary control is loosened. The generated app ships with the full baseline **enforced in code** — `src/main/index.ts` (wiring), `src/main/policy.ts` (rules, pure and unit-tested), `forge.config.ts` (fuses). This reference explains each control so changes preserve it; the canonical statement is `docs/principles/stack/electron/security.md`.
|
|
20
|
+
|
|
21
|
+
The controls fail **as a set**: enabling `nodeIntegration` silently disables the sandbox for that renderer. There is no safe partial loosening.
|
|
22
|
+
|
|
23
|
+
## The Hardened Quartet
|
|
24
|
+
|
|
25
|
+
```ts
|
|
26
|
+
webPreferences: {
|
|
27
|
+
contextIsolation: true, // never off
|
|
28
|
+
sandbox: true, // never off
|
|
29
|
+
nodeIntegration: false, // never on
|
|
30
|
+
webSecurity: true, // never off — not even "temporarily for dev"
|
|
31
|
+
},
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
These are Electron's own defaults, restated explicitly so no upgrade, flag, or debugging session changes them silently. They apply to **every** window (`references/process-model.md` → Adding a Window). The framework's generation tests assert the generated main never contains a loosened value — treat the same assertion as a review rule for hand-written changes.
|
|
35
|
+
|
|
36
|
+
`webSecurity: false` and `allowRunningInsecureContent` as debugging crutches are how production apps ship with the front door open. Fix the content.
|
|
37
|
+
|
|
38
|
+
## Permissions: Denied by Default
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
session.defaultSession.setPermissionRequestHandler((_wc, _permission, callback) => {
|
|
42
|
+
callback(false);
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Electron's default **grants** permissions (camera, microphone, geolocation) to any content that asks; in a desktop app, content that asks unexpectedly is the attack. Granting a permission is a product decision: extend the handler with an explicit `permission === '...'` allowlist and a comment recording why — never remove the handler.
|
|
47
|
+
|
|
48
|
+
## Navigation and window.open
|
|
49
|
+
|
|
50
|
+
Two hooks in `applySecurityPolicy`, registered on `web-contents-created` so they cover every window automatically:
|
|
51
|
+
|
|
52
|
+
- **`will-navigate`** blocks navigation unless `isTrustedNavigationTarget` allows it — the bundle protocol always, the dev-server origin only while developing. A renderer that can reach an attacker's page hands the attacker a privileged-adjacent context.
|
|
53
|
+
- **`setWindowOpenHandler`** returns `{ action: 'deny' }` unconditionally; allowlisted https links are handed to `shell.openExternal` (the OS browser) instead of becoming Electron windows.
|
|
54
|
+
|
|
55
|
+
New in-app routes need no changes (the SPA never navigates the top frame). A legitimate new navigation target (e.g. an OAuth window) is a change to `policy.ts` with a test in `policy.test.ts`, not an inline exemption.
|
|
56
|
+
|
|
57
|
+
## shell.openExternal Allowlist
|
|
58
|
+
|
|
59
|
+
`shell.openExternal` launches whatever the OS associates with the input — `file:`, `smb:`, custom scheme handlers, anything. It is therefore only ever called on URLs that pass `isAllowedExternalUrl` (https-only baseline). Widening the allowlist is a recorded decision in `policy.ts` + test, per scheme, never a pass-through. The renderer can request it through the validated `shell:open-external` channel; it cannot reach `shell` any other way.
|
|
60
|
+
|
|
61
|
+
## The Custom Protocol
|
|
62
|
+
|
|
63
|
+
Packaged app content is served over `app://` (`registerBundleProtocol`), never `file://` — `file://` grants origin-level access to the filesystem namespace and breaks standard web security semantics. The handler resolves requests against the built renderer directory and rejects anything failing the `isContainedPath` traversal check.
|
|
64
|
+
|
|
65
|
+
In dev, electron-vite serves the renderer over `ELECTRON_RENDERER_URL`; the policy treats that origin as trusted only when the env var exists (i.e. never in a packaged build).
|
|
66
|
+
|
|
67
|
+
## Content-Security-Policy
|
|
68
|
+
|
|
69
|
+
`src/renderer/index.html` ships a strict CSP via `<meta http-equiv>` (the right mechanism for custom-protocol content):
|
|
70
|
+
|
|
71
|
+
```
|
|
72
|
+
default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data:
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This strictness is achievable because **all privileged data flows over IPC, not fetch** — the renderer has no business calling the network. Keep it that way: a feature that "needs" `connect-src` should route through main (`references/ipc-contracts.md` → Core Access). A CSP containing `*` is no CSP. `style-src 'unsafe-inline'` carries Vite's dev-mode style injection; scripts stay `'self'`-only in every mode.
|
|
76
|
+
|
|
77
|
+
## Fuses
|
|
78
|
+
|
|
79
|
+
Fuses are build-time switches baked into the binary — runtime config cannot re-enable what a fuse removed. They are flipped inside the Forge packaging step (`forge.config.ts`), so an unfused binary cannot reach a release channel:
|
|
80
|
+
|
|
81
|
+
| Fuse | Setting | Why |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| `RunAsNode` | **off** | The shipped binary must not double as a general-purpose Node executable |
|
|
84
|
+
| `EnableNodeOptionsEnvironmentVariable` | **off** | Blocks `NODE_OPTIONS` injection |
|
|
85
|
+
| `EnableCookieEncryption` | **on** | At-rest cookie protection |
|
|
86
|
+
| `EnableEmbeddedAsarIntegrityValidation` | **on** | CVE-2025-55305: heap-snapshot tampering backdoored Signal/Slack/1Password past code-integrity checks; ASAR integrity is the fix |
|
|
87
|
+
| `OnlyLoadAppFromAsar` | **on** | Companion to integrity validation — no side-loaded app directory |
|
|
88
|
+
| `nodeCliInspect` | **on, deliberately** | Flipping it off breaks Playwright's `_electron` launch; the agent-closable smoke loop outranks the marginal hardening |
|
|
89
|
+
|
|
90
|
+
Post-CVE-2025-55305, shipping without ASAR integrity is called out as a defect, not a hardening opportunity. Do not move fuse flipping out of the packaging pipeline into a checklist.
|
|
91
|
+
|
|
92
|
+
## The Currency Window
|
|
93
|
+
|
|
94
|
+
Only the latest **three** Electron majors receive security patches, and a new major ships every 8 weeks — Chromium CVEs land in the shipped app on Chromium's schedule, not the team's. An app more than three majors behind is running known-exploitable browser bugs. Treat the upgrade as scheduled work with dependency-CVE priority; verify the Playwright driver pairing in CI when bumping (driver/Electron launch regressions have happened — e.g. the 36.x launch failure fixed in 37).
|
|
95
|
+
|
|
96
|
+
## Security Review Checklist
|
|
97
|
+
|
|
98
|
+
For any PR touching `src/main/`, `src/preload/`, `forge.config.ts`, or `index.html`:
|
|
99
|
+
|
|
100
|
+
- [ ] Quartet untouched in every `BrowserWindow`
|
|
101
|
+
- [ ] No new `ipcMain.handle` without sender validation; zod on non-trivial payloads
|
|
102
|
+
- [ ] Preload still exposes only purpose-named methods — no `ipcRenderer`, no generic passthrough
|
|
103
|
+
- [ ] Navigation/permission/external-URL changes live in `policy.ts` with tests
|
|
104
|
+
- [ ] CSP not weakened; no new `connect-src`
|
|
105
|
+
- [ ] Content still served over `app://`
|
|
106
|
+
- [ ] Fuse config unchanged (or the change is a recorded decision)
|
|
107
|
+
- [ ] No renderer/shared import of Electron or Node (lint must stay green without suppressions)
|