groundwork-method 0.0.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (629) hide show
  1. package/CHANGELOG.md +781 -0
  2. package/LICENSE +21 -0
  3. package/README.md +44 -29
  4. package/bin/groundwork.js +1654 -0
  5. package/dist/src/generators/add-capability/generator.d.ts +8 -0
  6. package/dist/src/generators/add-capability/generator.js +60 -0
  7. package/dist/src/generators/add-capability/generator.js.map +1 -0
  8. package/dist/src/generators/cli-app/generator.d.ts +9 -0
  9. package/dist/src/generators/cli-app/generator.js +140 -0
  10. package/dist/src/generators/cli-app/generator.js.map +1 -0
  11. package/dist/src/generators/docs-site/generator.d.ts +5 -0
  12. package/dist/src/generators/docs-site/generator.js +441 -0
  13. package/dist/src/generators/docs-site/generator.js.map +1 -0
  14. package/dist/src/generators/electron-app/generator.d.ts +6 -0
  15. package/dist/src/generators/electron-app/generator.js +261 -0
  16. package/dist/src/generators/electron-app/generator.js.map +1 -0
  17. package/dist/src/generators/flutter-app/generator.d.ts +6 -0
  18. package/dist/src/generators/flutter-app/generator.js +314 -0
  19. package/dist/src/generators/flutter-app/generator.js.map +1 -0
  20. package/dist/src/generators/go-microservice/generator.d.ts +8 -0
  21. package/dist/src/generators/go-microservice/generator.js +232 -0
  22. package/dist/src/generators/go-microservice/generator.js.map +1 -0
  23. package/dist/src/generators/nextjs-app/generator.d.ts +8 -0
  24. package/dist/src/generators/nextjs-app/generator.js +294 -0
  25. package/dist/src/generators/nextjs-app/generator.js.map +1 -0
  26. package/dist/src/generators/python-microservice/generator.d.ts +13 -0
  27. package/dist/src/generators/python-microservice/generator.js +265 -0
  28. package/dist/src/generators/python-microservice/generator.js.map +1 -0
  29. package/dist/src/generators/shared/brand-tokens.d.ts +89 -0
  30. package/dist/src/generators/shared/brand-tokens.js +308 -0
  31. package/dist/src/generators/shared/brand-tokens.js.map +1 -0
  32. package/dist/src/generators/shared/capabilities.d.ts +101 -0
  33. package/dist/src/generators/shared/capabilities.js +279 -0
  34. package/dist/src/generators/shared/capabilities.js.map +1 -0
  35. package/dist/src/generators/shared/provenance.d.ts +2 -0
  36. package/dist/src/generators/shared/provenance.js +85 -0
  37. package/dist/src/generators/shared/provenance.js.map +1 -0
  38. package/dist/src/generators/shared/scaffold-helpers.d.ts +72 -0
  39. package/dist/src/generators/shared/scaffold-helpers.js +309 -0
  40. package/dist/src/generators/shared/scaffold-helpers.js.map +1 -0
  41. package/dist/src/generators/system-test-runner/generator.d.ts +23 -0
  42. package/dist/src/generators/system-test-runner/generator.js +125 -0
  43. package/dist/src/generators/system-test-runner/generator.js.map +1 -0
  44. package/dist/src/generators/workspace-dev-cli/generator.d.ts +7 -0
  45. package/dist/src/generators/workspace-dev-cli/generator.js +138 -0
  46. package/dist/src/generators/workspace-dev-cli/generator.js.map +1 -0
  47. package/generators.json +57 -0
  48. package/lib/repo-map/grammars/tree-sitter-c.wasm +0 -0
  49. package/lib/repo-map/grammars/tree-sitter-cpp.wasm +0 -0
  50. package/lib/repo-map/grammars/tree-sitter-csharp.wasm +0 -0
  51. package/lib/repo-map/grammars/tree-sitter-dart.wasm +0 -0
  52. package/lib/repo-map/grammars/tree-sitter-go.wasm +0 -0
  53. package/lib/repo-map/grammars/tree-sitter-java.wasm +0 -0
  54. package/lib/repo-map/grammars/tree-sitter-javascript.wasm +0 -0
  55. package/lib/repo-map/grammars/tree-sitter-kotlin.wasm +0 -0
  56. package/lib/repo-map/grammars/tree-sitter-lua.wasm +0 -0
  57. package/lib/repo-map/grammars/tree-sitter-php.wasm +0 -0
  58. package/lib/repo-map/grammars/tree-sitter-python.wasm +0 -0
  59. package/lib/repo-map/grammars/tree-sitter-ruby.wasm +0 -0
  60. package/lib/repo-map/grammars/tree-sitter-rust.wasm +0 -0
  61. package/lib/repo-map/grammars/tree-sitter-scala.wasm +0 -0
  62. package/lib/repo-map/grammars/tree-sitter-swift.wasm +0 -0
  63. package/lib/repo-map/grammars/tree-sitter-tsx.wasm +0 -0
  64. package/lib/repo-map/grammars/tree-sitter-typescript.wasm +0 -0
  65. package/lib/repo-map/index.js +386 -0
  66. package/lib/repo-map/languages.js +514 -0
  67. package/lib/repo-map/pagerank.js +59 -0
  68. package/migrations/README.md +60 -0
  69. package/migrations/_template/cli-migration.js +27 -0
  70. package/migrations/gw-bet-prose-redesign.js +105 -0
  71. package/migrations/gw-drop-test-manifest.js +37 -0
  72. package/migrations/gw-register-serena-mcp.js +42 -0
  73. package/migrations/gw-relocate-hidden-skills.js +40 -0
  74. package/migrations/gw-seed-config-toml.js +24 -0
  75. package/migrations/index.json +40 -0
  76. package/package.json +70 -6
  77. package/src/AGENTS.md +36 -0
  78. package/src/config/config.toml +30 -0
  79. package/src/config/groundwork-state.json +5 -0
  80. package/src/docs/llms.txt +72 -0
  81. package/src/docs/principles/ai-native/agent-native-systems.md +90 -0
  82. package/src/docs/principles/ai-native/agentic-systems.md +78 -0
  83. package/src/docs/principles/ai-native/ai-engineering.md +100 -0
  84. package/src/docs/principles/ai-native/ai-native-product.md +76 -0
  85. package/src/docs/principles/delivery/cost-engineering.md +89 -0
  86. package/src/docs/principles/delivery/day-2-operational-baseline.md +57 -0
  87. package/src/docs/principles/delivery/devex.md +88 -0
  88. package/src/docs/principles/delivery/platform.md +101 -0
  89. package/src/docs/principles/delivery/progressive-delivery.md +92 -0
  90. package/src/docs/principles/design/ai-native-design.md +73 -0
  91. package/src/docs/principles/design/design-foundations.md +80 -0
  92. package/src/docs/principles/design/design-systems-and-tokens.md +72 -0
  93. package/src/docs/principles/design/interaction-and-motion.md +69 -0
  94. package/src/docs/principles/design/layout-and-space.md +72 -0
  95. package/src/docs/principles/design/usability-and-ux.md +68 -0
  96. package/src/docs/principles/design/visual-design.md +84 -0
  97. package/src/docs/principles/foundations/code-craft.md +86 -0
  98. package/src/docs/principles/foundations/continuous-discovery.md +75 -0
  99. package/src/docs/principles/foundations/documentation.md +102 -0
  100. package/src/docs/principles/foundations/prioritization-and-appetite.md +78 -0
  101. package/src/docs/principles/foundations/product-engineering.md +90 -0
  102. package/src/docs/principles/foundations/product-risks.md +89 -0
  103. package/src/docs/principles/foundations/requirements-and-specs.md +80 -0
  104. package/src/docs/principles/foundations/success-metrics.md +66 -0
  105. package/src/docs/principles/foundations/testing.md +82 -0
  106. package/src/docs/principles/index.md +23 -0
  107. package/src/docs/principles/quality/accessibility.md +88 -0
  108. package/src/docs/principles/quality/observability.md +84 -0
  109. package/src/docs/principles/quality/performance.md +84 -0
  110. package/src/docs/principles/quality/privacy.md +92 -0
  111. package/src/docs/principles/quality/reliability.md +89 -0
  112. package/src/docs/principles/quality/security.md +78 -0
  113. package/src/docs/principles/stack/postgres.md +100 -0
  114. package/src/docs/principles/system-design/api-design.md +86 -0
  115. package/src/docs/principles/system-design/architecture-decisions.md +81 -0
  116. package/src/docs/principles/system-design/code-structure.md +104 -0
  117. package/src/docs/principles/system-design/data-engineering.md +87 -0
  118. package/src/docs/principles/system-design/durable-execution.md +89 -0
  119. package/src/docs/principles/system-design/evolutionary-architecture.md +81 -0
  120. package/src/docs/principles/system-design/identity-and-access.md +76 -0
  121. package/src/docs/principles/system-design/integration-patterns.md +84 -0
  122. package/src/docs/principles/system-design/real-time.md +83 -0
  123. package/src/docs/principles/system-design/surface-architecture.md +74 -0
  124. package/src/docs/ways-of-working/documentation.md +69 -0
  125. package/src/docs/ways-of-working/how-we-work.md +76 -0
  126. package/src/docs/ways-of-working/units-of-work.md +40 -0
  127. package/src/engineer-skills/groundwork-electron-engineer/SKILL.md +118 -0
  128. package/src/engineer-skills/groundwork-electron-engineer/references/ipc-contracts.md +138 -0
  129. package/src/engineer-skills/groundwork-electron-engineer/references/packaging-and-updates.md +82 -0
  130. package/src/engineer-skills/groundwork-electron-engineer/references/process-model.md +94 -0
  131. package/src/engineer-skills/groundwork-electron-engineer/references/security.md +107 -0
  132. package/src/engineer-skills/groundwork-electron-engineer/references/testing-and-smoke.md +107 -0
  133. package/src/engineer-skills/groundwork-electron-engineer/references/theming-and-tokens.md +74 -0
  134. package/src/engineer-skills/groundwork-electron-engineer/sync-anchor.md +14 -0
  135. package/src/engineer-skills/groundwork-flutter-engineer/SKILL.md +108 -0
  136. package/src/engineer-skills/groundwork-flutter-engineer/references/accessibility.md +92 -0
  137. package/src/engineer-skills/groundwork-flutter-engineer/references/architecture.md +189 -0
  138. package/src/engineer-skills/groundwork-flutter-engineer/references/data-and-contracts.md +136 -0
  139. package/src/engineer-skills/groundwork-flutter-engineer/references/navigation.md +122 -0
  140. package/src/engineer-skills/groundwork-flutter-engineer/references/platform-channels.md +93 -0
  141. package/src/engineer-skills/groundwork-flutter-engineer/references/releases-and-distribution.md +84 -0
  142. package/src/engineer-skills/groundwork-flutter-engineer/references/state-management.md +166 -0
  143. package/src/engineer-skills/groundwork-flutter-engineer/references/testing.md +135 -0
  144. package/src/engineer-skills/groundwork-flutter-engineer/references/theming-and-design-tokens.md +109 -0
  145. package/src/engineer-skills/groundwork-flutter-engineer/references/widgets-and-composition.md +123 -0
  146. package/src/engineer-skills/groundwork-flutter-engineer/sync-anchor.md +15 -0
  147. package/src/engineer-skills/groundwork-go-engineer/SKILL.md +171 -0
  148. package/src/engineer-skills/groundwork-go-engineer/references/api-design.md +82 -0
  149. package/src/engineer-skills/groundwork-go-engineer/references/architecture.md +42 -0
  150. package/src/engineer-skills/groundwork-go-engineer/references/capability-ports.md +50 -0
  151. package/src/engineer-skills/groundwork-go-engineer/references/code-craft-security.md +34 -0
  152. package/src/engineer-skills/groundwork-go-engineer/references/concurrency.md +108 -0
  153. package/src/engineer-skills/groundwork-go-engineer/references/go-services.md +77 -0
  154. package/src/engineer-skills/groundwork-go-engineer/references/http-handlers.md +172 -0
  155. package/src/engineer-skills/groundwork-go-engineer/references/implementation-patterns.md +156 -0
  156. package/src/engineer-skills/groundwork-go-engineer/references/integration-realtime-data.md +57 -0
  157. package/src/engineer-skills/groundwork-go-engineer/references/observability.md +49 -0
  158. package/src/engineer-skills/groundwork-go-engineer/references/postgres.md +41 -0
  159. package/src/engineer-skills/groundwork-go-engineer/references/reliability-performance.md +105 -0
  160. package/src/engineer-skills/groundwork-go-engineer/references/testing.md +139 -0
  161. package/src/engineer-skills/groundwork-go-engineer/sync-anchor.md +11 -0
  162. package/src/engineer-skills/groundwork-nextjs-engineer/SKILL.md +107 -0
  163. package/src/engineer-skills/groundwork-nextjs-engineer/references/architecture.md +323 -0
  164. package/src/engineer-skills/groundwork-nextjs-engineer/references/data-fetching.md +458 -0
  165. package/src/engineer-skills/groundwork-nextjs-engineer/references/documentation.md +324 -0
  166. package/src/engineer-skills/groundwork-nextjs-engineer/references/error-boundaries.md +383 -0
  167. package/src/engineer-skills/groundwork-nextjs-engineer/references/mutations-and-forms.md +396 -0
  168. package/src/engineer-skills/groundwork-nextjs-engineer/references/performance-and-deployment.md +947 -0
  169. package/src/engineer-skills/groundwork-nextjs-engineer/references/routing-and-navigation.md +405 -0
  170. package/src/engineer-skills/groundwork-nextjs-engineer/references/server-components.md +394 -0
  171. package/src/engineer-skills/groundwork-nextjs-engineer/references/tailwind-and-styling.md +134 -0
  172. package/src/engineer-skills/groundwork-nextjs-engineer/references/testing.md +433 -0
  173. package/src/engineer-skills/groundwork-nextjs-engineer/references/type-system.md +368 -0
  174. package/src/engineer-skills/groundwork-nextjs-engineer/references/ux-principles.md +278 -0
  175. package/src/engineer-skills/groundwork-nextjs-engineer/references/visual-language.md +69 -0
  176. package/src/engineer-skills/groundwork-nextjs-engineer/sync-anchor.md +9 -0
  177. package/src/engineer-skills/groundwork-python-engineer/SKILL.md +196 -0
  178. package/src/engineer-skills/groundwork-python-engineer/references/api-standards.md +88 -0
  179. package/src/engineer-skills/groundwork-python-engineer/references/architecture.md +57 -0
  180. package/src/engineer-skills/groundwork-python-engineer/references/async-patterns.md +103 -0
  181. package/src/engineer-skills/groundwork-python-engineer/references/capability-ports.md +44 -0
  182. package/src/engineer-skills/groundwork-python-engineer/references/database.md +88 -0
  183. package/src/engineer-skills/groundwork-python-engineer/references/documentation-mcp.md +167 -0
  184. package/src/engineer-skills/groundwork-python-engineer/references/implementation-patterns.md +166 -0
  185. package/src/engineer-skills/groundwork-python-engineer/references/ml-pipelines.md +119 -0
  186. package/src/engineer-skills/groundwork-python-engineer/references/ml-systems-ai-engineering.md +74 -0
  187. package/src/engineer-skills/groundwork-python-engineer/references/observability.md +57 -0
  188. package/src/engineer-skills/groundwork-python-engineer/references/resilience.md +126 -0
  189. package/src/engineer-skills/groundwork-python-engineer/references/testing.md +177 -0
  190. package/src/engineer-skills/groundwork-python-engineer/sync-anchor.md +13 -0
  191. package/src/generators/add-capability/generator.ts +70 -0
  192. package/src/generators/add-capability/schema.json +30 -0
  193. package/src/generators/capabilities/llm/capability.json +28 -0
  194. package/src/generators/capabilities/llm/providers/anthropic/footprint.json +13 -0
  195. package/src/generators/capabilities/llm/providers/anthropic/stacks/go/internal/llm/llm.go.template +102 -0
  196. package/src/generators/capabilities/llm/providers/anthropic/stacks/python/src/__packageName__/adapters/llm.py.template +61 -0
  197. package/src/generators/capabilities/llm/providers/local/footprint.json +13 -0
  198. package/src/generators/capabilities/llm/providers/local/stacks/go/internal/llm/llm.go.template +102 -0
  199. package/src/generators/capabilities/llm/providers/local/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  200. package/src/generators/capabilities/llm/providers/localai/footprint.json +29 -0
  201. package/src/generators/capabilities/llm/providers/localai/stacks/go/internal/llm/llm.go.template +102 -0
  202. package/src/generators/capabilities/llm/providers/localai/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  203. package/src/generators/capabilities/llm/providers/none/footprint.json +9 -0
  204. package/src/generators/capabilities/llm/providers/none/stacks/go/internal/llm/llm.go.template +35 -0
  205. package/src/generators/capabilities/llm/providers/none/stacks/python/src/__packageName__/adapters/llm.py.template +25 -0
  206. package/src/generators/capabilities/llm/providers/ollama/footprint.json +20 -0
  207. package/src/generators/capabilities/llm/providers/ollama/stacks/go/internal/llm/llm.go.template +102 -0
  208. package/src/generators/capabilities/llm/providers/ollama/stacks/python/src/__packageName__/adapters/llm.py.template +53 -0
  209. package/src/generators/capabilities/llm/providers/openai/footprint.json +13 -0
  210. package/src/generators/capabilities/llm/providers/openai/stacks/go/internal/llm/llm.go.template +98 -0
  211. package/src/generators/capabilities/llm/providers/openai/stacks/python/src/__packageName__/adapters/llm.py.template +60 -0
  212. package/src/generators/capabilities/llm/stacks/go/internal/core/service/llm.go.template +12 -0
  213. package/src/generators/capabilities/llm/stacks/go/internal/llm/llm_test.go.template +33 -0
  214. package/src/generators/capabilities/llm/stacks/python/src/__packageName__/core/llm.py.template +15 -0
  215. package/src/generators/capabilities/llm/stacks/python/tests/contracts/test_llm.py.template +37 -0
  216. package/src/generators/cli-app/files/README.md.template +76 -0
  217. package/src/generators/cli-app/files/build.mjs.template +15 -0
  218. package/src/generators/cli-app/files/package.json.template +21 -0
  219. package/src/generators/cli-app/files/src/cli.ts.template +67 -0
  220. package/src/generators/cli-app/files/src/commands/hello.ts.template +17 -0
  221. package/src/generators/cli-app/files/src/commands/status.ts.template +23 -0
  222. package/src/generators/cli-app/files/src/core/client.test.ts.template +80 -0
  223. package/src/generators/cli-app/files/src/core/client.ts.template +64 -0
  224. package/src/generators/cli-app/files/src/registry.test.ts.template +35 -0
  225. package/src/generators/cli-app/files/src/registry.ts.template +31 -0
  226. package/src/generators/cli-app/files/tsconfig.json.template +16 -0
  227. package/src/generators/cli-app/files/tsconfig.test.json.template +11 -0
  228. package/src/generators/cli-app/generator.ts +138 -0
  229. package/src/generators/cli-app/schema.json +24 -0
  230. package/src/generators/docs-site/files/.gitignore.ejs +40 -0
  231. package/src/generators/docs-site/files/app/docs/__slug__/page.tsx +101 -0
  232. package/src/generators/docs-site/files/app/docs/layout.tsx +14 -0
  233. package/src/generators/docs-site/files/app/docs.css +43 -0
  234. package/src/generators/docs-site/files/app/layout.tsx +24 -0
  235. package/src/generators/docs-site/files/app/page.tsx +135 -0
  236. package/src/generators/docs-site/files/app/source.ts +8 -0
  237. package/src/generators/docs-site/files/components/mermaid.tsx +67 -0
  238. package/src/generators/docs-site/files/next.config.mjs +10 -0
  239. package/src/generators/docs-site/files/package.json +32 -0
  240. package/src/generators/docs-site/files/pnpm-workspace.yaml +7 -0
  241. package/src/generators/docs-site/files/postcss.config.mjs +6 -0
  242. package/src/generators/docs-site/files/source.config.ts +77 -0
  243. package/src/generators/docs-site/files/tailwind.config.js +10 -0
  244. package/src/generators/docs-site/files/tsconfig.json +27 -0
  245. package/src/generators/docs-site/generator.ts +476 -0
  246. package/src/generators/docs-site/schema.json +17 -0
  247. package/src/generators/electron-app/docs/principles/stack/electron/index.md +47 -0
  248. package/src/generators/electron-app/docs/principles/stack/electron/ipc-contracts.md +71 -0
  249. package/src/generators/electron-app/docs/principles/stack/electron/packaging-and-updates.md +59 -0
  250. package/src/generators/electron-app/docs/principles/stack/electron/process-model.md +53 -0
  251. package/src/generators/electron-app/docs/principles/stack/electron/security.md +70 -0
  252. package/src/generators/electron-app/docs/principles/stack/typescript/frontend.md +65 -0
  253. package/src/generators/electron-app/files/.gitignore.template +20 -0
  254. package/src/generators/electron-app/files/README.md.template +125 -0
  255. package/src/generators/electron-app/files/electron.vite.config.ts +31 -0
  256. package/src/generators/electron-app/files/eslint.config.mjs +92 -0
  257. package/src/generators/electron-app/files/forge.config.ts.template +44 -0
  258. package/src/generators/electron-app/files/package.json.template +54 -0
  259. package/src/generators/electron-app/files/playwright.config.ts +18 -0
  260. package/src/generators/electron-app/files/project.json.template +65 -0
  261. package/src/generators/electron-app/files/src/main/core-client.test.ts +81 -0
  262. package/src/generators/electron-app/files/src/main/core-client.ts +55 -0
  263. package/src/generators/electron-app/files/src/main/index.ts +157 -0
  264. package/src/generators/electron-app/files/src/main/ipc.ts +52 -0
  265. package/src/generators/electron-app/files/src/main/policy.test.ts +71 -0
  266. package/src/generators/electron-app/files/src/main/policy.ts +73 -0
  267. package/src/generators/electron-app/files/src/preload/index.ts +23 -0
  268. package/src/generators/electron-app/files/src/renderer/index.html.template +20 -0
  269. package/src/generators/electron-app/files/src/renderer/src/App.test.tsx +61 -0
  270. package/src/generators/electron-app/files/src/renderer/src/App.tsx.template +43 -0
  271. package/src/generators/electron-app/files/src/renderer/src/assets/main.css +40 -0
  272. package/src/generators/electron-app/files/src/renderer/src/env.d.ts +14 -0
  273. package/src/generators/electron-app/files/src/renderer/src/main.tsx +25 -0
  274. package/src/generators/electron-app/files/src/shared/ipc.ts +54 -0
  275. package/src/generators/electron-app/files/tests/smoke/app.spec.ts.template +68 -0
  276. package/src/generators/electron-app/files/tool/electron_exec.sh.template +83 -0
  277. package/src/generators/electron-app/files/tsconfig.json +7 -0
  278. package/src/generators/electron-app/files/tsconfig.node.json +27 -0
  279. package/src/generators/electron-app/files/tsconfig.web.json +22 -0
  280. package/src/generators/electron-app/files/vitest.config.ts +32 -0
  281. package/src/generators/electron-app/files/vitest.setup.ts +1 -0
  282. package/src/generators/electron-app/generator.ts +288 -0
  283. package/src/generators/electron-app/schema.json +23 -0
  284. package/src/generators/flutter-app/docs/principles/stack/flutter/architecture.md +78 -0
  285. package/src/generators/flutter-app/docs/principles/stack/flutter/index.md +38 -0
  286. package/src/generators/flutter-app/docs/principles/stack/flutter/platform-channels.md +51 -0
  287. package/src/generators/flutter-app/docs/principles/stack/flutter/releases-and-distribution.md +59 -0
  288. package/src/generators/flutter-app/docs/principles/stack/flutter/state-management.md +85 -0
  289. package/src/generators/flutter-app/docs/principles/stack/flutter/testing.md +74 -0
  290. package/src/generators/flutter-app/docs/principles/stack/flutter/widgets-and-composition.md +69 -0
  291. package/src/generators/flutter-app/files/.gitignore.template +30 -0
  292. package/src/generators/flutter-app/files/README.md.template +100 -0
  293. package/src/generators/flutter-app/files/analysis_options.yaml.template +18 -0
  294. package/src/generators/flutter-app/files/integration_test/app_test.dart.template +30 -0
  295. package/src/generators/flutter-app/files/lib/app.dart.template +24 -0
  296. package/src/generators/flutter-app/files/lib/config/app_config.dart +15 -0
  297. package/src/generators/flutter-app/files/lib/data/repositories/status_repository.dart +36 -0
  298. package/src/generators/flutter-app/files/lib/data/services/api_client.dart +71 -0
  299. package/src/generators/flutter-app/files/lib/domain/models/health_status.dart +23 -0
  300. package/src/generators/flutter-app/files/lib/main.dart +11 -0
  301. package/src/generators/flutter-app/files/lib/router.dart +23 -0
  302. package/src/generators/flutter-app/files/lib/ui/core/theme/app_theme.dart +110 -0
  303. package/src/generators/flutter-app/files/lib/ui/home/home_view.dart +89 -0
  304. package/src/generators/flutter-app/files/lib/ui/home/home_view_model.dart.template +38 -0
  305. package/src/generators/flutter-app/files/project.json.template +51 -0
  306. package/src/generators/flutter-app/files/pubspec.yaml.template +47 -0
  307. package/src/generators/flutter-app/files/test/api_client_test.dart.template +63 -0
  308. package/src/generators/flutter-app/files/test/fakes/fake_status_repository.dart.template +19 -0
  309. package/src/generators/flutter-app/files/test/home_view_test.dart.template +58 -0
  310. package/src/generators/flutter-app/files/tool/flutter_exec.sh.template +60 -0
  311. package/src/generators/flutter-app/generator.ts +362 -0
  312. package/src/generators/flutter-app/schema.json +23 -0
  313. package/src/generators/go-microservice/docs/principles/stack/go/concurrency.md +123 -0
  314. package/src/generators/go-microservice/docs/principles/stack/go/index.md +70 -0
  315. package/src/generators/go-microservice/docs/principles/stack/go/testing.md +152 -0
  316. package/src/generators/go-microservice/files/.air.toml.template +38 -0
  317. package/src/generators/go-microservice/files/.env.template +4 -0
  318. package/src/generators/go-microservice/files/.golangci.yml.template +82 -0
  319. package/src/generators/go-microservice/files/Dockerfile.dev.template +12 -0
  320. package/src/generators/go-microservice/files/asyncapi-pubsub.yaml.template +33 -0
  321. package/src/generators/go-microservice/files/asyncapi-ws.yaml.template +34 -0
  322. package/src/generators/go-microservice/files/cmd/api/main.go.template +149 -0
  323. package/src/generators/go-microservice/files/cmd/api/main_test.go.template +99 -0
  324. package/src/generators/go-microservice/files/cmd/worker/cleanup/main.go.template +39 -0
  325. package/src/generators/go-microservice/files/db/schema.sql.template +24 -0
  326. package/src/generators/go-microservice/files/go.mod.template +39 -0
  327. package/src/generators/go-microservice/files/internal/config/config.go.template +52 -0
  328. package/src/generators/go-microservice/files/internal/config/otel.go.template +93 -0
  329. package/src/generators/go-microservice/files/internal/core/domain/errors.go.template +16 -0
  330. package/src/generators/go-microservice/files/internal/core/domain/model.go.template +28 -0
  331. package/src/generators/go-microservice/files/internal/core/domain/user.go.template +13 -0
  332. package/src/generators/go-microservice/files/internal/core/pagination.go.template +16 -0
  333. package/src/generators/go-microservice/files/internal/core/service/app_service.go.template +79 -0
  334. package/src/generators/go-microservice/files/internal/core/service/event_hub.go.template +9 -0
  335. package/src/generators/go-microservice/files/internal/core/service/message_queue.go.template +10 -0
  336. package/src/generators/go-microservice/files/internal/core/service/outbox_repository.go.template +31 -0
  337. package/src/generators/go-microservice/files/internal/core/service/repository.go.template +23 -0
  338. package/src/generators/go-microservice/files/internal/core/service/user_repository.go.template +15 -0
  339. package/src/generators/go-microservice/files/internal/core/service/user_service.go.template +43 -0
  340. package/src/generators/go-microservice/files/internal/entrypoints/api/app_handler.go.template +108 -0
  341. package/src/generators/go-microservice/files/internal/entrypoints/api/auth_middleware_test.go.template +52 -0
  342. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook.go.template +202 -0
  343. package/src/generators/go-microservice/files/internal/entrypoints/api/clerk_webhook_test.go.template +82 -0
  344. package/src/generators/go-microservice/files/internal/entrypoints/api/health_handler.go.template +80 -0
  345. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware.go.template +87 -0
  346. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/middleware_test.go.template +76 -0
  347. package/src/generators/go-microservice/files/internal/entrypoints/api/idempotency/repository.go.template +37 -0
  348. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_auth.go.template +40 -0
  349. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_loadshed.go.template +38 -0
  350. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_logging.go.template +40 -0
  351. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_ratelimit.go.template +48 -0
  352. package/src/generators/go-microservice/files/internal/entrypoints/api/middleware_test.go.template +81 -0
  353. package/src/generators/go-microservice/files/internal/entrypoints/api/router.go.template +105 -0
  354. package/src/generators/go-microservice/files/internal/entrypoints/api/types.go.template +70 -0
  355. package/src/generators/go-microservice/files/internal/entrypoints/api/websocket_handler.go.template +39 -0
  356. package/src/generators/go-microservice/files/internal/httpclient/http_client.go.template +87 -0
  357. package/src/generators/go-microservice/files/internal/kafka/kafka.go.template +34 -0
  358. package/src/generators/go-microservice/files/internal/postgres/postgres.go.template +195 -0
  359. package/src/generators/go-microservice/files/internal/postgres/postgres_test.go.template +156 -0
  360. package/src/generators/go-microservice/files/internal/postgres/user_repository.go.template +56 -0
  361. package/src/generators/go-microservice/files/internal/pubsub/gcp_pubsub.go.template +35 -0
  362. package/src/generators/go-microservice/files/internal/websocket/client.go.template +151 -0
  363. package/src/generators/go-microservice/files/internal/websocket/hub.go.template +261 -0
  364. package/src/generators/go-microservice/files/scripts/apply-schema.sh.template +21 -0
  365. package/src/generators/go-microservice/files/tools/tools.go.template +10 -0
  366. package/src/generators/go-microservice/generator.ts +240 -0
  367. package/src/generators/go-microservice/schema.json +63 -0
  368. package/src/generators/nextjs-app/docs/principles/stack/typescript/frontend.md +65 -0
  369. package/src/generators/nextjs-app/files/.dockerignore.template +7 -0
  370. package/src/generators/nextjs-app/files/.env.example.template +24 -0
  371. package/src/generators/nextjs-app/files/.gitignore.template +5 -0
  372. package/src/generators/nextjs-app/files/Dockerfile +53 -0
  373. package/src/generators/nextjs-app/files/app/(auth)/sign-in/__sign-in__/page.tsx.template +9 -0
  374. package/src/generators/nextjs-app/files/app/(auth)/sign-up/__sign-up__/page.tsx.template +9 -0
  375. package/src/generators/nextjs-app/files/app/api/config/route.ts.template +39 -0
  376. package/src/generators/nextjs-app/files/app/api/healthz/route.test.ts +15 -0
  377. package/src/generators/nextjs-app/files/app/api/healthz/route.ts +5 -0
  378. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.test.ts.template +55 -0
  379. package/src/generators/nextjs-app/files/app/api/proxy/__path__/route.ts.template +126 -0
  380. package/src/generators/nextjs-app/files/app/error.tsx +39 -0
  381. package/src/generators/nextjs-app/files/app/global-error.tsx +68 -0
  382. package/src/generators/nextjs-app/files/app/globals.css +105 -0
  383. package/src/generators/nextjs-app/files/app/layout.tsx +59 -0
  384. package/src/generators/nextjs-app/files/app/loading.tsx +13 -0
  385. package/src/generators/nextjs-app/files/app/not-found.tsx +30 -0
  386. package/src/generators/nextjs-app/files/app/page.tsx +20 -0
  387. package/src/generators/nextjs-app/files/components/providers/default.tsx +19 -0
  388. package/src/generators/nextjs-app/files/components/providers/production.tsx +32 -0
  389. package/src/generators/nextjs-app/files/components/providers/telemetry.tsx +76 -0
  390. package/src/generators/nextjs-app/files/components/render-smoke.test.tsx +29 -0
  391. package/src/generators/nextjs-app/files/components/theme-provider.tsx +11 -0
  392. package/src/generators/nextjs-app/files/components.json +21 -0
  393. package/src/generators/nextjs-app/files/eslint.config.mjs +120 -0
  394. package/src/generators/nextjs-app/files/hooks/use-toast.ts +7 -0
  395. package/src/generators/nextjs-app/files/instrumentation.ts +90 -0
  396. package/src/generators/nextjs-app/files/lib/api/fetcher.ts.template +130 -0
  397. package/src/generators/nextjs-app/files/lib/config.ts +21 -0
  398. package/src/generators/nextjs-app/files/lib/logger.ts +29 -0
  399. package/src/generators/nextjs-app/files/lib/schemas/index.ts +19 -0
  400. package/src/generators/nextjs-app/files/lib/utils.ts +6 -0
  401. package/src/generators/nextjs-app/files/next.config.mjs +9 -0
  402. package/src/generators/nextjs-app/files/package.json +70 -0
  403. package/src/generators/nextjs-app/files/postcss.config.mjs +8 -0
  404. package/src/generators/nextjs-app/files/proxy.test.ts.template +30 -0
  405. package/src/generators/nextjs-app/files/proxy.ts +31 -0
  406. package/src/generators/nextjs-app/files/public/.gitkeep +1 -0
  407. package/src/generators/nextjs-app/files/tsconfig.json +42 -0
  408. package/src/generators/nextjs-app/files/vitest.config.mts +15 -0
  409. package/src/generators/nextjs-app/files/vitest.setup.ts +7 -0
  410. package/src/generators/nextjs-app/generator.ts +307 -0
  411. package/src/generators/nextjs-app/schema.json +44 -0
  412. package/src/generators/python-microservice/docs/principles/stack/python/async.md +168 -0
  413. package/src/generators/python-microservice/docs/principles/stack/python/documentation.md +240 -0
  414. package/src/generators/python-microservice/docs/principles/stack/python/mcp.md +147 -0
  415. package/src/generators/python-microservice/docs/principles/stack/python/resilience.md +193 -0
  416. package/src/generators/python-microservice/docs/principles/stack/python/testing.md +281 -0
  417. package/src/generators/python-microservice/files/.env.example.template +30 -0
  418. package/src/generators/python-microservice/files/Dockerfile.template +36 -0
  419. package/src/generators/python-microservice/files/db/schema.sql.template +19 -0
  420. package/src/generators/python-microservice/files/pyproject.toml.template +76 -0
  421. package/src/generators/python-microservice/files/scripts/apply-schema.sh.template +25 -0
  422. package/src/generators/python-microservice/files/src/__packageName__/adapters/comfyui.py.template +87 -0
  423. package/src/generators/python-microservice/files/src/__packageName__/adapters/config.py.template +48 -0
  424. package/src/generators/python-microservice/files/src/__packageName__/adapters/database.py.template +21 -0
  425. package/src/generators/python-microservice/files/src/__packageName__/adapters/message_queue.py.template +29 -0
  426. package/src/generators/python-microservice/files/src/__packageName__/adapters/repository.py.template +130 -0
  427. package/src/generators/python-microservice/files/src/__packageName__/adapters/telemetry.py.template +68 -0
  428. package/src/generators/python-microservice/files/src/__packageName__/adapters/websocket_hub.py.template +36 -0
  429. package/src/generators/python-microservice/files/src/__packageName__/core/domain/entities.py.template +22 -0
  430. package/src/generators/python-microservice/files/src/__packageName__/core/domain/exceptions.py.template +43 -0
  431. package/src/generators/python-microservice/files/src/__packageName__/core/ports.py.template +42 -0
  432. package/src/generators/python-microservice/files/src/__packageName__/core/service/example_service.py.template +68 -0
  433. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/dependencies.py.template +50 -0
  434. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/middleware.py.template +131 -0
  435. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/router.py.template +37 -0
  436. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/api/websocket_handler.py.template +20 -0
  437. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/cleanup.py.template +35 -0
  438. package/src/generators/python-microservice/files/src/__packageName__/entrypoints/worker/worker.py.template +28 -0
  439. package/src/generators/python-microservice/files/src/__packageName__/main.py.template +108 -0
  440. package/src/generators/python-microservice/files/tests/test_main.py.template +74 -0
  441. package/src/generators/python-microservice/files/tests/test_middleware.py.template +109 -0
  442. package/src/generators/python-microservice/files/tests/test_worker.py.template +16 -0
  443. package/src/generators/python-microservice/generator.ts +286 -0
  444. package/src/generators/python-microservice/schema.json +86 -0
  445. package/src/generators/shared/brand-tokens.ts +301 -0
  446. package/src/generators/shared/capabilities.ts +349 -0
  447. package/src/generators/shared/provenance.ts +61 -0
  448. package/src/generators/shared/scaffold-helpers.ts +309 -0
  449. package/src/generators/system-test-runner/files/tests/bets/.gitkeep +0 -0
  450. package/src/generators/system-test-runner/files/tests/bets/_archive/.gitkeep +0 -0
  451. package/src/generators/system-test-runner/files/tests/conftest.py.template +503 -0
  452. package/src/generators/system-test-runner/files/tests/pyproject.toml.template +20 -0
  453. package/src/generators/system-test-runner/files/tests/system/pages/__init__.py.template +9 -0
  454. package/src/generators/system-test-runner/files/tests/system/pages/base_page.py.template +36 -0
  455. package/src/generators/system-test-runner/files/tests/system/test_a11y_smoke.py.template +132 -0
  456. package/src/generators/system-test-runner/files/tests/system/test_contract_conformance.py.template +140 -0
  457. package/src/generators/system-test-runner/files/tests/system/test_layout_geometry.py.template +109 -0
  458. package/src/generators/system-test-runner/files/tests/system/test_render_smoke.py.template +227 -0
  459. package/src/generators/system-test-runner/files/tests/system/test_system.py.template +158 -0
  460. package/src/generators/system-test-runner/files/tests/system/test_token_conformance.py.template +206 -0
  461. package/src/generators/system-test-runner/files/tests/system/test_visual_regression.py.template +104 -0
  462. package/src/generators/system-test-runner/generator.ts +142 -0
  463. package/src/generators/system-test-runner/schema.json +24 -0
  464. package/src/generators/workspace-dev-cli/cli-src/build.mjs +42 -0
  465. package/src/generators/workspace-dev-cli/cli-src/dist/dev-bundle.js +2168 -0
  466. package/src/generators/workspace-dev-cli/cli-src/src/commands/bet.ts +442 -0
  467. package/src/generators/workspace-dev-cli/cli-src/src/commands/completion.ts +87 -0
  468. package/src/generators/workspace-dev-cli/cli-src/src/commands/doctor.ts +139 -0
  469. package/src/generators/workspace-dev-cli/cli-src/src/commands/lifecycle.ts +548 -0
  470. package/src/generators/workspace-dev-cli/cli-src/src/commands/quality.ts +127 -0
  471. package/src/generators/workspace-dev-cli/cli-src/src/commands/surface.ts +214 -0
  472. package/src/generators/workspace-dev-cli/cli-src/src/index.ts +127 -0
  473. package/src/generators/workspace-dev-cli/cli-src/src/registry.ts +194 -0
  474. package/src/generators/workspace-dev-cli/cli-src/src/theme/color.ts +130 -0
  475. package/src/generators/workspace-dev-cli/cli-src/src/theme/render.ts +158 -0
  476. package/src/generators/workspace-dev-cli/cli-src/src/theme/tokens.ts +122 -0
  477. package/src/generators/workspace-dev-cli/cli-src/src/util/context.ts +43 -0
  478. package/src/generators/workspace-dev-cli/cli-src/src/util/extensions.ts +99 -0
  479. package/src/generators/workspace-dev-cli/cli-src/src/util/paths.ts +46 -0
  480. package/src/generators/workspace-dev-cli/cli-src/src/util/proc.ts +106 -0
  481. package/src/generators/workspace-dev-cli/cli-src/src/util/prompt.ts +108 -0
  482. package/src/generators/workspace-dev-cli/cli-src/src/util/runners.ts +70 -0
  483. package/src/generators/workspace-dev-cli/cli-src/src/util/services.ts +221 -0
  484. package/src/generators/workspace-dev-cli/cli-src/src/util/version.ts +21 -0
  485. package/src/generators/workspace-dev-cli/cli-src/tsconfig.json +16 -0
  486. package/src/generators/workspace-dev-cli/files/.agents/skills/workspace-cli/SKILL.md.template +74 -0
  487. package/src/generators/workspace-dev-cli/files/dev.template +16 -0
  488. package/src/generators/workspace-dev-cli/files/docker-compose.yml.template +20 -0
  489. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/milestone-test.pytmpl.template +46 -0
  490. package/src/generators/workspace-dev-cli/files/scripts/cli/templates/slice-test.pytmpl.template +38 -0
  491. package/src/generators/workspace-dev-cli/generator.ts +136 -0
  492. package/src/generators/workspace-dev-cli/schema.json +22 -0
  493. package/src/hidden-skills/code-intelligence.md +129 -0
  494. package/src/hidden-skills/groundwork-architect/SKILL.md +114 -0
  495. package/src/hidden-skills/groundwork-architect/references/agentic-systems.md +44 -0
  496. package/src/hidden-skills/groundwork-architect/references/ai-native-architecture.md +37 -0
  497. package/src/hidden-skills/groundwork-architect/references/api-and-contracts.md +45 -0
  498. package/src/hidden-skills/groundwork-architect/references/core-and-boundaries.md +45 -0
  499. package/src/hidden-skills/groundwork-architect/references/data-architecture.md +33 -0
  500. package/src/hidden-skills/groundwork-architect/references/decision-records.md +34 -0
  501. package/src/hidden-skills/groundwork-architect/references/durable-execution.md +45 -0
  502. package/src/hidden-skills/groundwork-architect/references/evolutionary-architecture.md +37 -0
  503. package/src/hidden-skills/groundwork-architect/references/identity-and-access.md +41 -0
  504. package/src/hidden-skills/groundwork-architect/references/integration-patterns.md +39 -0
  505. package/src/hidden-skills/groundwork-architect/references/observability.md +36 -0
  506. package/src/hidden-skills/groundwork-architect/references/performance-and-scale.md +41 -0
  507. package/src/hidden-skills/groundwork-architect/references/platform-and-delivery.md +47 -0
  508. package/src/hidden-skills/groundwork-architect/references/realtime-and-async.md +28 -0
  509. package/src/hidden-skills/groundwork-architect/references/reliability.md +31 -0
  510. package/src/hidden-skills/groundwork-architect/references/security-and-trust.md +47 -0
  511. package/src/hidden-skills/groundwork-architect/references/surface-architecture.md +40 -0
  512. package/src/hidden-skills/groundwork-architect/sync-anchor.md +34 -0
  513. package/src/hidden-skills/groundwork-architecture/architecture-template.md +50 -0
  514. package/src/hidden-skills/groundwork-architecture/instructions.md +139 -0
  515. package/src/hidden-skills/groundwork-architecture/phases/01-context-ingestion.md +18 -0
  516. package/src/hidden-skills/groundwork-architecture/phases/02-technical-constraints.md +27 -0
  517. package/src/hidden-skills/groundwork-architecture/phases/03-service-design.md +19 -0
  518. package/src/hidden-skills/groundwork-architecture/phases/04-data-flow-communication.md +23 -0
  519. package/src/hidden-skills/groundwork-architecture/phases/05-component-boundaries-contracts.md +17 -0
  520. package/src/hidden-skills/groundwork-architecture/phases/06-draft-review-present.md +38 -0
  521. package/src/hidden-skills/groundwork-architecture/phases/07-commit.md +33 -0
  522. package/src/hidden-skills/groundwork-architecture/templates/architecture-cache.md +43 -0
  523. package/src/hidden-skills/groundwork-architecture-extract/instructions.md +163 -0
  524. package/src/hidden-skills/groundwork-architecture-extract/templates/architecture-extract-cache.md +21 -0
  525. package/src/hidden-skills/groundwork-bet/briefs/slice-worker.md +191 -0
  526. package/src/hidden-skills/groundwork-bet/instructions.md +88 -0
  527. package/src/hidden-skills/groundwork-bet/templates/bet-progress-test.md +126 -0
  528. package/src/hidden-skills/groundwork-bet/templates/change-proposal.md +38 -0
  529. package/src/hidden-skills/groundwork-bet/templates/decomposition/meta.json +4 -0
  530. package/src/hidden-skills/groundwork-bet/templates/decomposition/milestone-index.md +35 -0
  531. package/src/hidden-skills/groundwork-bet/templates/decomposition/slice.md +35 -0
  532. package/src/hidden-skills/groundwork-bet/templates/pitch.md +45 -0
  533. package/src/hidden-skills/groundwork-bet/templates/technical-design/01-ui-design.md +51 -0
  534. package/src/hidden-skills/groundwork-bet/templates/technical-design/02-data-flows.md +36 -0
  535. package/src/hidden-skills/groundwork-bet/templates/technical-design/03-api-design.md +90 -0
  536. package/src/hidden-skills/groundwork-bet/templates/technical-design/04-data-design.md +29 -0
  537. package/src/hidden-skills/groundwork-bet/workflows/01-discovery.md +198 -0
  538. package/src/hidden-skills/groundwork-bet/workflows/02-design.md +168 -0
  539. package/src/hidden-skills/groundwork-bet/workflows/03-decomposition.md +246 -0
  540. package/src/hidden-skills/groundwork-bet/workflows/04-delivery.md +193 -0
  541. package/src/hidden-skills/groundwork-bet/workflows/05-validation.md +199 -0
  542. package/src/hidden-skills/groundwork-design-system/instructions.md +125 -0
  543. package/src/hidden-skills/groundwork-design-system/templates/brand-tokens.md +182 -0
  544. package/src/hidden-skills/groundwork-design-system/templates/design-system-cache.md +64 -0
  545. package/src/hidden-skills/groundwork-design-system/tracks/_foundation.md +136 -0
  546. package/src/hidden-skills/groundwork-design-system/tracks/agentic-protocol.md +269 -0
  547. package/src/hidden-skills/groundwork-design-system/tracks/cli.md +355 -0
  548. package/src/hidden-skills/groundwork-design-system/tracks/graphical-ui.md +330 -0
  549. package/src/hidden-skills/groundwork-design-system-extract/instructions.md +124 -0
  550. package/src/hidden-skills/groundwork-design-system-extract/templates/design-system-extract-cache.md +19 -0
  551. package/src/hidden-skills/groundwork-designer/SKILL.md +108 -0
  552. package/src/hidden-skills/groundwork-designer/references/accessibility.md +33 -0
  553. package/src/hidden-skills/groundwork-designer/references/ai-native-design.md +37 -0
  554. package/src/hidden-skills/groundwork-designer/references/design-review.md +29 -0
  555. package/src/hidden-skills/groundwork-designer/references/design-systems-and-tokens.md +33 -0
  556. package/src/hidden-skills/groundwork-designer/references/interaction-and-motion.md +37 -0
  557. package/src/hidden-skills/groundwork-designer/references/layout-and-space.md +33 -0
  558. package/src/hidden-skills/groundwork-designer/references/usability-and-ux.md +33 -0
  559. package/src/hidden-skills/groundwork-designer/references/visual-craft.md +49 -0
  560. package/src/hidden-skills/groundwork-designer/sync-anchor.md +20 -0
  561. package/src/hidden-skills/groundwork-doc-sync/instructions.md +100 -0
  562. package/src/hidden-skills/groundwork-elicit/instructions.md +66 -0
  563. package/src/hidden-skills/groundwork-elicit/methods.md +65 -0
  564. package/src/hidden-skills/groundwork-infra-adopt/instructions.md +168 -0
  565. package/src/hidden-skills/groundwork-infra-adopt/templates/infra-adopt-cache.md +21 -0
  566. package/src/hidden-skills/groundwork-mvp/instructions.md +223 -0
  567. package/src/hidden-skills/groundwork-mvp/templates/mvp-cache.md +9 -0
  568. package/src/hidden-skills/groundwork-patch/instructions.md +40 -0
  569. package/src/hidden-skills/groundwork-persona/instructions.md +54 -0
  570. package/src/hidden-skills/groundwork-product/SKILL.md +102 -0
  571. package/src/hidden-skills/groundwork-product/references/ai-native-product.md +45 -0
  572. package/src/hidden-skills/groundwork-product/references/discovery-and-opportunity.md +38 -0
  573. package/src/hidden-skills/groundwork-product/references/product-risks.md +52 -0
  574. package/src/hidden-skills/groundwork-product/references/requirements-and-specs.md +39 -0
  575. package/src/hidden-skills/groundwork-product/references/scope-and-sequencing.md +35 -0
  576. package/src/hidden-skills/groundwork-product/references/shaping-and-appetite.md +48 -0
  577. package/src/hidden-skills/groundwork-product/references/success-metrics-and-signals.md +37 -0
  578. package/src/hidden-skills/groundwork-product/sync-anchor.md +19 -0
  579. package/src/hidden-skills/groundwork-product-brief/instructions.md +231 -0
  580. package/src/hidden-skills/groundwork-product-brief-extract/instructions.md +139 -0
  581. package/src/hidden-skills/groundwork-product-brief-extract/templates/product-brief-extract-cache.md +17 -0
  582. package/src/hidden-skills/groundwork-review/checklists/architecture.md +93 -0
  583. package/src/hidden-skills/groundwork-review/checklists/bet-pitch.md +94 -0
  584. package/src/hidden-skills/groundwork-review/checklists/decomposition.md +135 -0
  585. package/src/hidden-skills/groundwork-review/checklists/design-system.md +85 -0
  586. package/src/hidden-skills/groundwork-review/checklists/domain-entity.md +66 -0
  587. package/src/hidden-skills/groundwork-review/checklists/implementation-readiness.md +46 -0
  588. package/src/hidden-skills/groundwork-review/checklists/infrastructure.md +68 -0
  589. package/src/hidden-skills/groundwork-review/checklists/maturity.md +71 -0
  590. package/src/hidden-skills/groundwork-review/checklists/product-brief.md +69 -0
  591. package/src/hidden-skills/groundwork-review/checklists/technical-design.md +112 -0
  592. package/src/hidden-skills/groundwork-review/instructions.md +181 -0
  593. package/src/hidden-skills/groundwork-scaffold/instructions.md +254 -0
  594. package/src/hidden-skills/groundwork-scaffold/phases/01-ingestion-service-mapping.md +87 -0
  595. package/src/hidden-skills/groundwork-scaffold/phases/02-scaffolding-execution.md +15 -0
  596. package/src/hidden-skills/groundwork-scaffold/phases/03-service-documentation-api-stubs.md +100 -0
  597. package/src/hidden-skills/groundwork-scaffold/phases/04-infrastructure-verification.md +17 -0
  598. package/src/hidden-skills/groundwork-scaffold/phases/05-draft-review.md +19 -0
  599. package/src/hidden-skills/groundwork-scaffold/phases/06-commit.md +19 -0
  600. package/src/hidden-skills/groundwork-scaffold/templates/scaffold-cache.md +23 -0
  601. package/src/hidden-skills/groundwork-scan/instructions.md +164 -0
  602. package/src/hidden-skills/groundwork-scan/references/digest-schema.md +66 -0
  603. package/src/hidden-skills/groundwork-scan/references/exclusions.md +44 -0
  604. package/src/hidden-skills/groundwork-scan/templates/architecture-findings.md +42 -0
  605. package/src/hidden-skills/groundwork-scan/templates/design-findings.md +23 -0
  606. package/src/hidden-skills/groundwork-scan/templates/overview.md +26 -0
  607. package/src/hidden-skills/groundwork-scan/templates/product-findings.md +23 -0
  608. package/src/hidden-skills/groundwork-scan/templates/scan-state.json +19 -0
  609. package/src/hidden-skills/groundwork-stack-forge/instructions.md +150 -0
  610. package/src/hidden-skills/groundwork-stack-forge/references/authoring-engineer-skills.md +107 -0
  611. package/src/hidden-skills/groundwork-surface-activation/instructions.md +138 -0
  612. package/src/hidden-skills/groundwork-update/briefs/reconcile-worker.md +196 -0
  613. package/src/hidden-skills/groundwork-update/instructions.md +200 -0
  614. package/src/hidden-skills/groundwork-writer/SKILL.md +278 -0
  615. package/src/hidden-skills/maturity-model.md +125 -0
  616. package/src/hidden-skills/operating-contract.md +400 -0
  617. package/src/hidden-skills/repo-map-schema.md +90 -0
  618. package/src/hidden-skills/templates/adr.md +57 -0
  619. package/src/hidden-skills/templates/capability-ports.md +71 -0
  620. package/src/hidden-skills/templates/discovery-notes.md +33 -0
  621. package/src/hidden-skills/templates/domain-entity.md +80 -0
  622. package/src/hidden-skills/templates/gap-ledger.md +21 -0
  623. package/src/hidden-skills/templates/handoff.md +37 -0
  624. package/src/hidden-skills/templates/maturity.md +39 -0
  625. package/src/hidden-skills/templates/surfaces.md +207 -0
  626. package/src/skills/groundwork-check/SKILL.md +56 -0
  627. package/src/skills/groundwork-check/instructions.md +70 -0
  628. package/src/skills/groundwork-orchestrator/SKILL.md +176 -0
  629. package/src/skills/groundwork-orchestrator/workflow-index.md +50 -0
@@ -0,0 +1,44 @@
1
+ import type { ForgeConfig } from '@electron-forge/shared-types';
2
+ import { MakerZIP } from '@electron-forge/maker-zip';
3
+ import { FusesPlugin } from '@electron-forge/plugin-fuses';
4
+ import { FuseV1Options, FuseVersion } from '@electron/fuses';
5
+
6
+ // Packaging is where the security posture becomes physical: fuses are flipped
7
+ // inside this pipeline so an unhardened binary cannot reach a release channel
8
+ // (docs/principles/stack/electron/packaging-and-updates.md). Run `electron-vite
9
+ // build` before packaging — package.json's `main` points at the built output.
10
+ //
11
+ // Code signing is non-optional for release builds (macOS Developer ID +
12
+ // notarytool, Windows Azure Artifact Signing); wire osxSign/osxNotarize and the
13
+ // Windows signing hook here when release credentials exist. An unsigned build
14
+ // is a development artifact, never a release.
15
+ const config: ForgeConfig = {
16
+ packagerConfig: {
17
+ asar: true,
18
+ appBundleId: '<%= appId %>',
19
+ },
20
+ makers: [new MakerZIP({}, ['darwin', 'linux', 'win32'])],
21
+ plugins: [
22
+ new FusesPlugin({
23
+ version: FuseVersion.V1,
24
+ // The shipped binary must not double as a general-purpose Node
25
+ // executable (docs/principles/stack/electron/security.md).
26
+ [FuseV1Options.RunAsNode]: false,
27
+ [FuseV1Options.EnableCookieEncryption]: true,
28
+ [FuseV1Options.EnableNodeOptionsEnvironmentVariable]: false,
29
+ // Left ON deliberately: flipping nodeCliInspect off breaks Playwright's
30
+ // _electron launch, and the agent-closable smoke loop outranks the
31
+ // marginal hardening (docs/principles/stack/electron/security.md).
32
+ [FuseV1Options.EnableNodeCliInspectArguments]: true,
33
+ // CVE-2025-55305: local V8 heap-snapshot tampering backdoored Signal,
34
+ // Slack, and 1Password past their code-integrity checks. ASAR integrity
35
+ // validation + asar-only load is the fix; shipping without it is a
36
+ // defect, not a hardening opportunity
37
+ // (docs/principles/stack/electron/security.md).
38
+ [FuseV1Options.EnableEmbeddedAsarIntegrityValidation]: true,
39
+ [FuseV1Options.OnlyLoadAppFromAsar]: true,
40
+ }),
41
+ ],
42
+ };
43
+
44
+ export default config;
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "<%= fileName %>",
3
+ "productName": "<%= name %>",
4
+ "version": "0.1.0",
5
+ "private": true,
6
+ "description": "Electron desktop surface scaffolded by GroundWork",
7
+ "main": "./out/main/index.js",
8
+ "scripts": {
9
+ "dev": "electron-vite dev",
10
+ "build": "electron-vite build",
11
+ "start": "electron-vite preview",
12
+ "lint": "eslint .",
13
+ "lint:fix": "eslint . --fix",
14
+ "typecheck": "tsc --noEmit -p tsconfig.node.json --composite false && tsc --noEmit -p tsconfig.web.json --composite false",
15
+ "test": "vitest run",
16
+ "test:watch": "vitest",
17
+ "smoke": "playwright test",
18
+ "package": "electron-forge package",
19
+ "make": "electron-forge make"
20
+ },
21
+ "dependencies": {
22
+ "@tanstack/react-query": "^5.90.0",
23
+ "react": "19.2.7",
24
+ "react-dom": "19.2.7",
25
+ "zod": "^3.24.1"
26
+ },
27
+ "devDependencies": {
28
+ "@electron-forge/cli": "^7.11.0",
29
+ "@electron-forge/maker-zip": "^7.11.0",
30
+ "@electron-forge/plugin-fuses": "^7.11.0",
31
+ "@electron/fuses": "^1.8.0",
32
+ "@playwright/test": "^1.60.0",
33
+ "@tailwindcss/vite": "^4.3.0",
34
+ "@testing-library/dom": "^10.4.1",
35
+ "@testing-library/jest-dom": "^6.9.1",
36
+ "@testing-library/react": "^16.3.2",
37
+ "@types/node": "^24.0.0",
38
+ "@types/react": "19.2.17",
39
+ "@types/react-dom": "19.2.3",
40
+ "@vitejs/plugin-react": "^5.2.0",
41
+ "electron": "^42.0.0",
42
+ "electron-vite": "^5.0.0",
43
+ "eslint": "^9.39.4",
44
+ "eslint-plugin-react-hooks": "^7.1.0",
45
+ "globals": "^17.4.0",
46
+ "jsdom": "^29.0.0",
47
+ "playwright": "^1.60.0",
48
+ "tailwindcss": "^4.3.0",
49
+ "typescript": "5.9.3",
50
+ "typescript-eslint": "^8.58.0",
51
+ "vite": "^7.3.0",
52
+ "vitest": "^4.1.0"
53
+ }
54
+ }
@@ -0,0 +1,18 @@
1
+ import { defineConfig } from '@playwright/test';
2
+
3
+ // Boot-tier smoke configuration. The suite launches this app's own Electron
4
+ // binary through Playwright's _electron driver — no browser downloads are
5
+ // needed (`playwright install` is not required). On Linux CI it runs under
6
+ // xvfb; tool/electron_exec.sh handles the display guard
7
+ // (docs/principles/stack/electron/security.md → testing references).
8
+ export default defineConfig({
9
+ testDir: './tests/smoke',
10
+ timeout: 60_000,
11
+ // The smoke drives one app instance; keep the lane serial and thin.
12
+ fullyParallel: false,
13
+ workers: 1,
14
+ use: {
15
+ screenshot: 'only-on-failure',
16
+ trace: 'retain-on-failure',
17
+ },
18
+ });
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "<%= fileName %>",
3
+ "$schema": "../../node_modules/nx/schemas/project-schema.json",
4
+ "projectType": "application",
5
+ "sourceRoot": "services/<%= fileName %>/src",
6
+ "tags": ["surface:desktop", "stack:electron"],
7
+ "targets": {
8
+ "bootstrap": {
9
+ "executor": "nx:run-commands",
10
+ "options": {
11
+ "command": "bash tool/electron_exec.sh bootstrap",
12
+ "cwd": "services/<%= fileName %>"
13
+ }
14
+ },
15
+ "run": {
16
+ "executor": "nx:run-commands",
17
+ "options": {
18
+ "command": "bash tool/electron_exec.sh run",
19
+ "cwd": "services/<%= fileName %>"
20
+ }
21
+ },
22
+ "build": {
23
+ "executor": "nx:run-commands",
24
+ "options": {
25
+ "command": "bash tool/electron_exec.sh build",
26
+ "cwd": "services/<%= fileName %>"
27
+ }
28
+ },
29
+ "lint": {
30
+ "executor": "nx:run-commands",
31
+ "options": {
32
+ "command": "bash tool/electron_exec.sh lint",
33
+ "cwd": "services/<%= fileName %>"
34
+ }
35
+ },
36
+ "typecheck": {
37
+ "executor": "nx:run-commands",
38
+ "options": {
39
+ "command": "bash tool/electron_exec.sh typecheck",
40
+ "cwd": "services/<%= fileName %>"
41
+ }
42
+ },
43
+ "test": {
44
+ "executor": "nx:run-commands",
45
+ "options": {
46
+ "command": "bash tool/electron_exec.sh test",
47
+ "cwd": "services/<%= fileName %>"
48
+ }
49
+ },
50
+ "smoke": {
51
+ "executor": "nx:run-commands",
52
+ "options": {
53
+ "command": "bash tool/electron_exec.sh smoke",
54
+ "cwd": "services/<%= fileName %>"
55
+ }
56
+ },
57
+ "package": {
58
+ "executor": "nx:run-commands",
59
+ "options": {
60
+ "command": "bash tool/electron_exec.sh package",
61
+ "cwd": "services/<%= fileName %>"
62
+ }
63
+ }
64
+ }
65
+ }
@@ -0,0 +1,81 @@
1
+ // The core-access seam is proven without a network: fetch is injected, so
2
+ // every reachability outcome (ok, non-200, thrown) is a deterministic case.
3
+ import { describe, expect, it } from 'vitest';
4
+ import {
5
+ DEFAULT_CORE_BASE_URL,
6
+ coreAuthHeaders,
7
+ coreBaseUrl,
8
+ fetchCoreHealth,
9
+ } from './core-client';
10
+
11
+ function fetchReturning(status: number, body: unknown): typeof fetch {
12
+ return (async () =>
13
+ new Response(JSON.stringify(body), {
14
+ status,
15
+ headers: { 'Content-Type': 'application/json' },
16
+ })) as typeof fetch;
17
+ }
18
+
19
+ describe('coreBaseUrl', () => {
20
+ it('defaults to the workspace gateway', () => {
21
+ expect(coreBaseUrl({})).toBe(DEFAULT_CORE_BASE_URL);
22
+ });
23
+
24
+ it('honours API_BASE_URL from the environment', () => {
25
+ expect(coreBaseUrl({ API_BASE_URL: 'http://10.0.0.5:4000' })).toBe(
26
+ 'http://10.0.0.5:4000',
27
+ );
28
+ });
29
+
30
+ it('treats a blank API_BASE_URL as unset', () => {
31
+ expect(coreBaseUrl({ API_BASE_URL: ' ' })).toBe(DEFAULT_CORE_BASE_URL);
32
+ });
33
+ });
34
+
35
+ describe('coreAuthHeaders', () => {
36
+ it('is unauthenticated by default', () => {
37
+ expect(coreAuthHeaders()).toEqual({});
38
+ });
39
+
40
+ it('carries a supplied token as a Bearer header', () => {
41
+ expect(coreAuthHeaders('jwt-123')).toEqual({
42
+ Authorization: 'Bearer jwt-123',
43
+ });
44
+ });
45
+ });
46
+
47
+ describe('fetchCoreHealth', () => {
48
+ it('maps a healthy core to reachable + its reported status', async () => {
49
+ const health = await fetchCoreHealth(
50
+ 'http://core.test',
51
+ fetchReturning(200, { status: 'ok', checks: { db: 'ok' } }),
52
+ );
53
+ expect(health).toEqual({ reachable: true, status: 'ok' });
54
+ });
55
+
56
+ it('requests the /health route of the configured base URL', async () => {
57
+ let requested: string | undefined;
58
+ const probe = (async (input: Parameters<typeof fetch>[0]) => {
59
+ requested = String(input);
60
+ return new Response('{"status":"ok"}', { status: 200 });
61
+ }) as typeof fetch;
62
+ await fetchCoreHealth('http://core.test:4000', probe);
63
+ expect(requested).toBe('http://core.test:4000/health');
64
+ });
65
+
66
+ it('maps a non-200 to unreachable with the code as the status', async () => {
67
+ const health = await fetchCoreHealth(
68
+ 'http://core.test',
69
+ fetchReturning(503, { error: 'overloaded' }),
70
+ );
71
+ expect(health).toEqual({ reachable: false, status: 'http 503' });
72
+ });
73
+
74
+ it('maps a network failure to a value, never a throw', async () => {
75
+ const down = (async () => {
76
+ throw new Error('ECONNREFUSED');
77
+ }) as typeof fetch;
78
+ const health = await fetchCoreHealth('http://core.test', down);
79
+ expect(health).toEqual({ reachable: false, status: 'unreachable' });
80
+ });
81
+ });
@@ -0,0 +1,55 @@
1
+ // The core-access seam: the ONLY place this app talks to the workspace
2
+ // gateway. The sandboxed renderer cannot reach the core directly (CSP locks
3
+ // it to the bundle origin), so it asks over the typed bridge and main makes
4
+ // the request — the desktop twin of the mobile scaffold's thin dio client
5
+ // (docs/principles/stack/electron/ipc-contracts.md).
6
+ //
7
+ // Contract-client stance (O8): hand-rolled and deliberately thin — one
8
+ // function per promoted-contract operation, typed results in src/shared/.
9
+ // When the promoted openapi.yaml grows past a handful of operations, switch
10
+ // to a generated TypeScript client and keep this module as the seam the IPC
11
+ // handlers consume — nothing across the bridge changes.
12
+ import type { CoreHealth } from '../shared/ipc';
13
+
14
+ export const DEFAULT_CORE_BASE_URL = 'http://localhost:4000';
15
+
16
+ /** Where the workspace core lives. The system-test harness (and any packaged
17
+ * environment) overrides via the API_BASE_URL environment variable. */
18
+ export function coreBaseUrl(env: NodeJS.ProcessEnv = process.env): string {
19
+ const configured = env['API_BASE_URL']?.trim();
20
+ return configured ? configured : DEFAULT_CORE_BASE_URL;
21
+ }
22
+
23
+ /** The auth seam: headers attached to every core request. Unauthenticated by
24
+ * default — wire your identity provider here (e.g. a session JWT becomes
25
+ * `Authorization: Bearer <token>`); the core's /health route stays public. */
26
+ export function coreAuthHeaders(token?: string): Record<string, string> {
27
+ return token ? { Authorization: `Bearer ${token}` } : {};
28
+ }
29
+
30
+ /** Probe the gateway's health endpoint — the wiring proof the renderer's
31
+ * home view displays. `/health` is what GroundWork's Go and Python cores
32
+ * serve; a Next.js BFF would be `/api/healthz` — adjust to your gateway.
33
+ * Failures map to a value, never a throw: an unreachable core is a state
34
+ * the UI renders, not an exception that kills the handler. */
35
+ export async function fetchCoreHealth(
36
+ baseUrl: string = coreBaseUrl(),
37
+ fetchImpl: typeof fetch = fetch,
38
+ ): Promise<CoreHealth> {
39
+ try {
40
+ const response = await fetchImpl(new URL('/health', baseUrl), {
41
+ headers: { Accept: 'application/json', ...coreAuthHeaders() },
42
+ signal: AbortSignal.timeout(5_000),
43
+ });
44
+ if (!response.ok) {
45
+ return { reachable: false, status: `http ${response.status}` };
46
+ }
47
+ const body = (await response.json()) as { status?: unknown };
48
+ return {
49
+ reachable: true,
50
+ status: typeof body.status === 'string' ? body.status : 'ok',
51
+ };
52
+ } catch {
53
+ return { reachable: false, status: 'unreachable' };
54
+ }
55
+ }
@@ -0,0 +1,157 @@
1
+ import {
2
+ app,
3
+ BrowserWindow,
4
+ nativeTheme,
5
+ net,
6
+ protocol,
7
+ session,
8
+ shell,
9
+ } from 'electron';
10
+ import * as path from 'node:path';
11
+ import { pathToFileURL } from 'node:url';
12
+ import { registerIpcHandlers } from './ipc';
13
+ import {
14
+ APP_ORIGIN,
15
+ APP_SCHEME,
16
+ isAllowedExternalUrl,
17
+ isContainedPath,
18
+ isTrustedNavigationTarget,
19
+ } from './policy';
20
+
21
+ // Main is an orchestrator and nothing more: window creation, security policy,
22
+ // IPC registration, OS integration. CPU-heavy or crash-prone work belongs in a
23
+ // utilityProcess with MessagePorts wired renderer↔utility directly — never
24
+ // here, where it would starve every window's event loop
25
+ // (docs/principles/stack/electron/process-model.md).
26
+
27
+ // Set by electron-vite during `dev`; absent in built/packaged runs.
28
+ const DEV_SERVER_URL = process.env['ELECTRON_RENDERER_URL'];
29
+
30
+ // Must run before app ready: the bundle protocol needs standard-scheme
31
+ // privileges so the renderer keeps ordinary web security semantics.
32
+ protocol.registerSchemesAsPrivileged([
33
+ {
34
+ scheme: APP_SCHEME,
35
+ privileges: { standard: true, secure: true, supportFetchAPI: true },
36
+ },
37
+ ]);
38
+
39
+ /** Serve the built renderer over the custom bundle protocol — never file://
40
+ * (docs/principles/stack/electron/security.md). Paths are resolved against
41
+ * the renderer output and containment-checked against traversal. */
42
+ function registerBundleProtocol(): void {
43
+ const rendererRoot = path.join(__dirname, '../renderer');
44
+ protocol.handle(APP_SCHEME, (request) => {
45
+ const { pathname } = new URL(request.url);
46
+ const requested = pathname === '/' ? '/index.html' : decodeURIComponent(pathname);
47
+ const target = path.resolve(rendererRoot, `.${requested}`);
48
+ if (!isContainedPath(rendererRoot, target, path.sep)) {
49
+ return new Response('Not found', { status: 404 });
50
+ }
51
+ return net.fetch(pathToFileURL(target).toString());
52
+ });
53
+ }
54
+
55
+ /** Global policy, registered before any window exists. */
56
+ function applySecurityPolicy(): void {
57
+ // Permission requests (camera, microphone, geolocation, ...) are denied by
58
+ // default — in a desktop app, content that asks unexpectedly is the attack.
59
+ // Grant individual permissions here only as a recorded product decision
60
+ // (docs/principles/stack/electron/security.md).
61
+ session.defaultSession.setPermissionRequestHandler(
62
+ (_webContents, _permission, callback) => {
63
+ callback(false);
64
+ },
65
+ );
66
+
67
+ app.on('web-contents-created', (_event, contents) => {
68
+ // Navigation away from app content is blocked outright.
69
+ contents.on('will-navigate', (event, url) => {
70
+ if (!isTrustedNavigationTarget(url, DEV_SERVER_URL)) {
71
+ event.preventDefault();
72
+ }
73
+ });
74
+ // window.open never creates an Electron window: allowlisted https links
75
+ // are handed to the OS browser; everything else is dropped.
76
+ contents.setWindowOpenHandler(({ url }) => {
77
+ if (isAllowedExternalUrl(url)) {
78
+ void shell.openExternal(url);
79
+ }
80
+ return { action: 'deny' };
81
+ });
82
+ });
83
+ }
84
+
85
+ function broadcastTheme(window: BrowserWindow): void {
86
+ window.webContents.send('theme:changed', {
87
+ shouldUseDarkColors: nativeTheme.shouldUseDarkColors,
88
+ });
89
+ }
90
+
91
+ function createWindow(): BrowserWindow {
92
+ const window = new BrowserWindow({
93
+ width: 1080,
94
+ height: 720,
95
+ show: false,
96
+ autoHideMenuBar: true,
97
+ webPreferences: {
98
+ preload: path.join(__dirname, '../preload/index.js'),
99
+ // The hardened quartet. These are Electron's own defaults, restated so
100
+ // no code path, flag, or debugging session ever loosens them — the
101
+ // controls fail as a set, not individually
102
+ // (docs/principles/stack/electron/security.md).
103
+ contextIsolation: true,
104
+ sandbox: true,
105
+ nodeIntegration: false,
106
+ webSecurity: true,
107
+ },
108
+ });
109
+
110
+ window.on('ready-to-show', () => window.show());
111
+ // Initial theme push once the renderer can receive it; updates are
112
+ // broadcast from the nativeTheme listener below.
113
+ window.webContents.on('did-finish-load', () => broadcastTheme(window));
114
+
115
+ if (DEV_SERVER_URL) {
116
+ void window.loadURL(DEV_SERVER_URL);
117
+ } else {
118
+ void window.loadURL(`${APP_ORIGIN}/`);
119
+ }
120
+ return window;
121
+ }
122
+
123
+ // Squirrel.Windows ties notifications and shortcuts to the AppUserModelID
124
+ // (docs/principles/stack/electron/packaging-and-updates.md).
125
+ if (process.platform === 'win32') {
126
+ app.setAppUserModelId('<%= appId %>');
127
+ }
128
+
129
+ void app.whenReady().then(() => {
130
+ if (!DEV_SERVER_URL) {
131
+ registerBundleProtocol();
132
+ }
133
+ applySecurityPolicy();
134
+ registerIpcHandlers(DEV_SERVER_URL);
135
+
136
+ // nativeTheme is the source of truth for dark mode; the renderer mirrors it
137
+ // onto <html data-theme> from this broadcast.
138
+ nativeTheme.on('updated', () => {
139
+ for (const window of BrowserWindow.getAllWindows()) {
140
+ broadcastTheme(window);
141
+ }
142
+ });
143
+
144
+ createWindow();
145
+
146
+ app.on('activate', () => {
147
+ if (BrowserWindow.getAllWindows().length === 0) {
148
+ createWindow();
149
+ }
150
+ });
151
+ });
152
+
153
+ app.on('window-all-closed', () => {
154
+ if (process.platform !== 'darwin') {
155
+ app.quit();
156
+ }
157
+ });
@@ -0,0 +1,52 @@
1
+ import { app, ipcMain, shell } from 'electron';
2
+ import { z } from 'zod';
3
+ import type { AppStatus, CoreHealth, OpenExternalResult } from '../shared/ipc';
4
+ import { fetchCoreHealth } from './core-client';
5
+ import { isAllowedExternalUrl, isTrustedSender } from './policy';
6
+
7
+ // Main treats renderer input as untrusted, the same way an API treats the
8
+ // public internet. Two checks in every handler: sender validation
9
+ // (event.senderFrame — checklist item 17), and zod payload validation for
10
+ // anything beyond a trivial getter, because compile-time types vanish at
11
+ // runtime and a compromised renderer is not bound by them
12
+ // (docs/principles/stack/electron/ipc-contracts.md).
13
+
14
+ const openExternalPayload = z.string().url();
15
+
16
+ function assertTrustedSender(
17
+ event: Electron.IpcMainInvokeEvent,
18
+ devServerUrl?: string,
19
+ ): void {
20
+ if (!isTrustedSender(event.senderFrame?.url, devServerUrl)) {
21
+ throw new Error('IPC call rejected: untrusted sender frame');
22
+ }
23
+ }
24
+
25
+ export function registerIpcHandlers(devServerUrl?: string): void {
26
+ ipcMain.handle('app:get-status', (event): AppStatus => {
27
+ assertTrustedSender(event, devServerUrl);
28
+ return {
29
+ status: 'ok',
30
+ version: app.getVersion(),
31
+ platform: process.platform,
32
+ };
33
+ });
34
+
35
+ ipcMain.handle('core:health', async (event): Promise<CoreHealth> => {
36
+ assertTrustedSender(event, devServerUrl);
37
+ return fetchCoreHealth();
38
+ });
39
+
40
+ ipcMain.handle(
41
+ 'shell:open-external',
42
+ async (event, rawUrl: unknown): Promise<OpenExternalResult> => {
43
+ assertTrustedSender(event, devServerUrl);
44
+ const url = openExternalPayload.parse(rawUrl);
45
+ if (!isAllowedExternalUrl(url)) {
46
+ return { opened: false };
47
+ }
48
+ await shell.openExternal(url);
49
+ return { opened: true };
50
+ },
51
+ );
52
+ }
@@ -0,0 +1,71 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import {
3
+ APP_ORIGIN,
4
+ isAllowedExternalUrl,
5
+ isContainedPath,
6
+ isTrustedNavigationTarget,
7
+ isTrustedSender,
8
+ } from './policy';
9
+
10
+ // The security policy is pure (no Electron imports), so the privileged
11
+ // decisions are proven in a plain Node environment. The boot smoke
12
+ // (tests/smoke/) proves the wiring; these tests prove the rules.
13
+
14
+ describe('isAllowedExternalUrl', () => {
15
+ it('allows https URLs', () => {
16
+ expect(isAllowedExternalUrl('https://example.com/docs')).toBe(true);
17
+ });
18
+
19
+ it.each([
20
+ 'http://example.com',
21
+ 'file:///etc/passwd',
22
+ 'javascript:alert(1)',
23
+ 'smb://attacker/share',
24
+ 'not a url',
25
+ '',
26
+ ])('rejects %s', (url) => {
27
+ expect(isAllowedExternalUrl(url)).toBe(false);
28
+ });
29
+ });
30
+
31
+ describe('isTrustedNavigationTarget', () => {
32
+ it('allows the bundle protocol', () => {
33
+ expect(isTrustedNavigationTarget(`${APP_ORIGIN}/index.html`)).toBe(true);
34
+ });
35
+
36
+ it('allows the dev server origin only while developing', () => {
37
+ expect(
38
+ isTrustedNavigationTarget('http://localhost:5173/', 'http://localhost:5173'),
39
+ ).toBe(true);
40
+ expect(isTrustedNavigationTarget('http://localhost:5173/')).toBe(false);
41
+ });
42
+
43
+ it('rejects everything else', () => {
44
+ expect(isTrustedNavigationTarget('https://attacker.example')).toBe(false);
45
+ expect(isTrustedNavigationTarget('file:///etc/passwd')).toBe(false);
46
+ expect(isTrustedNavigationTarget('')).toBe(false);
47
+ });
48
+ });
49
+
50
+ describe('isTrustedSender', () => {
51
+ it('rejects a missing frame (destroyed sender)', () => {
52
+ expect(isTrustedSender(undefined)).toBe(false);
53
+ });
54
+
55
+ it('accepts the app frame', () => {
56
+ expect(isTrustedSender(`${APP_ORIGIN}/`)).toBe(true);
57
+ });
58
+ });
59
+
60
+ describe('isContainedPath', () => {
61
+ it('accepts files inside the root', () => {
62
+ expect(isContainedPath('/out/renderer', '/out/renderer/index.html')).toBe(true);
63
+ expect(isContainedPath('/out/renderer', '/out/renderer/assets/app.css')).toBe(true);
64
+ });
65
+
66
+ it('rejects traversal escapes and the root itself', () => {
67
+ expect(isContainedPath('/out/renderer', '/out/secret.js')).toBe(false);
68
+ expect(isContainedPath('/out/renderer', '/out/renderer-evil/x')).toBe(false);
69
+ expect(isContainedPath('/out/renderer', '/out/renderer')).toBe(false);
70
+ });
71
+ });
@@ -0,0 +1,73 @@
1
+ // Pure security policy — no Electron imports, so every rule in this file is
2
+ // unit-testable in a plain Node environment (src/main/policy.test.ts) and the
3
+ // privileged decisions live in one reviewable place.
4
+
5
+ /** The custom protocol the packaged renderer is served over. file:// is never
6
+ * used: it grants origin-level filesystem access and breaks web security
7
+ * semantics (docs/principles/stack/electron/security.md). */
8
+ export const APP_SCHEME = 'app';
9
+ export const APP_ORIGIN = `${APP_SCHEME}://bundle`;
10
+
11
+ /** shell.openExternal launches whatever the OS associates with the input, so
12
+ * it only ever receives validated, allowlisted URLs. https-only is the
13
+ * baseline; widen it per-scheme as a recorded product decision, never with a
14
+ * pass-through. */
15
+ export function isAllowedExternalUrl(raw: string): boolean {
16
+ let url: URL;
17
+ try {
18
+ url = new URL(raw);
19
+ } catch {
20
+ return false;
21
+ }
22
+ return url.protocol === 'https:';
23
+ }
24
+
25
+ /** Navigation policy for will-navigate: app content stays on the bundle
26
+ * protocol (or the dev server while developing). Everything else is blocked —
27
+ * a renderer that can navigate to an attacker's page hands the attacker a
28
+ * privileged-adjacent context. */
29
+ export function isTrustedNavigationTarget(
30
+ raw: string,
31
+ devServerUrl?: string,
32
+ ): boolean {
33
+ let url: URL;
34
+ try {
35
+ url = new URL(raw);
36
+ } catch {
37
+ return false;
38
+ }
39
+ if (url.protocol === `${APP_SCHEME}:`) return true;
40
+ if (devServerUrl) {
41
+ try {
42
+ if (url.origin === new URL(devServerUrl).origin) return true;
43
+ } catch {
44
+ // unparseable dev URL — fall through to deny
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+
50
+ /** Sender validation for every IPC handler (security checklist item 17): the
51
+ * call must come from this app's own frame, not an iframe or a navigated-away
52
+ * window. A missing frame (destroyed sender) is rejected. */
53
+ export function isTrustedSender(
54
+ frameUrl: string | undefined,
55
+ devServerUrl?: string,
56
+ ): boolean {
57
+ if (!frameUrl) return false;
58
+ return isTrustedNavigationTarget(frameUrl, devServerUrl);
59
+ }
60
+
61
+ /** Containment check for the bundle protocol handler: the resolved path must
62
+ * stay inside the renderer output directory (no traversal escapes). The
63
+ * separator is a parameter so the rule stays pure and testable; callers pass
64
+ * path.sep. */
65
+ export function isContainedPath(
66
+ rootDir: string,
67
+ target: string,
68
+ sep = '/',
69
+ ): boolean {
70
+ if (target === rootDir) return false; // the root itself is not a file
71
+ const root = rootDir.endsWith(sep) ? rootDir : `${rootDir}${sep}`;
72
+ return target.startsWith(root);
73
+ }