create-win-project 1.3.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 (198) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +187 -0
  3. package/ci/expo.yml +28 -0
  4. package/ci/laravel.yml +49 -0
  5. package/ci/nextjs.yml +29 -0
  6. package/ci/springboot.yml +33 -0
  7. package/ci/vite.yml +36 -0
  8. package/compatibility/profiles.json +237 -0
  9. package/docs/ARCHITECTURE.md +118 -0
  10. package/docs/CONTENT_MODEL.md +36 -0
  11. package/docs/DEPENDENCY_MAINTENANCE.md +31 -0
  12. package/index.js +431 -0
  13. package/lib/application-shapes.js +95 -0
  14. package/lib/banner.js +45 -0
  15. package/lib/catalog.js +343 -0
  16. package/lib/compatibility.js +116 -0
  17. package/lib/constants.js +3 -0
  18. package/lib/doctor.js +45 -0
  19. package/lib/files.js +158 -0
  20. package/lib/generator.js +366 -0
  21. package/lib/interview.js +77 -0
  22. package/lib/laravel-scaffold.js +3 -0
  23. package/lib/playbooks.js +172 -0
  24. package/lib/project-location.js +18 -0
  25. package/lib/scaffold.js +467 -0
  26. package/lib/stacks/context.js +27 -0
  27. package/lib/stacks/contract.js +142 -0
  28. package/lib/stacks/index.js +8 -0
  29. package/lib/stacks/laravel/architecture.js +27 -0
  30. package/lib/stacks/laravel/auth/oidc.js +13 -0
  31. package/lib/stacks/laravel/auth/public.js +28 -0
  32. package/lib/stacks/laravel/auth/sanctum.js +14 -0
  33. package/lib/stacks/laravel/auth/session.js +17 -0
  34. package/lib/stacks/laravel/composer.js +50 -0
  35. package/lib/stacks/laravel/generate.js +362 -0
  36. package/lib/stacks/laravel/index.js +18 -0
  37. package/lib/stacks/laravel/ui/blade.js +15 -0
  38. package/lib/stacks/laravel/ui/index.js +29 -0
  39. package/lib/stacks/laravel/ui/inertia-react.js +35 -0
  40. package/lib/stacks/laravel/ui/livewire.js +39 -0
  41. package/lib/stacks/laravel/ui/shared.js +14 -0
  42. package/lib/stacks/registry.js +42 -0
  43. package/lib/stacks/shared/contributions.js +25 -0
  44. package/lib/template.js +62 -0
  45. package/package.json +49 -0
  46. package/playbooks/INDEX.md +58 -0
  47. package/playbooks/capabilities/auth/oidc-resource-server.md +15 -0
  48. package/playbooks/capabilities/auth/spring-session.md +15 -0
  49. package/playbooks/capabilities/ci/github-actions.manifest.json +10 -0
  50. package/playbooks/capabilities/ci/github-actions.md +61 -0
  51. package/playbooks/capabilities/docker/docker.manifest.json +11 -0
  52. package/playbooks/capabilities/docker/overview.md +55 -0
  53. package/playbooks/capabilities/flyway/environments.md +5 -0
  54. package/playbooks/capabilities/flyway/flyway.manifest.json +12 -0
  55. package/playbooks/capabilities/flyway/migrations.md +7 -0
  56. package/playbooks/capabilities/flyway/testing.md +5 -0
  57. package/playbooks/capabilities/laravel/database.md +8 -0
  58. package/playbooks/capabilities/laravel/migrations.md +15 -0
  59. package/playbooks/capabilities/laravel/observability.md +8 -0
  60. package/playbooks/capabilities/laravel/oidc-resource-server.md +10 -0
  61. package/playbooks/capabilities/laravel/queues.md +8 -0
  62. package/playbooks/capabilities/laravel/sanctum-spa.md +8 -0
  63. package/playbooks/capabilities/laravel/scheduler.md +7 -0
  64. package/playbooks/capabilities/laravel/session-auth.md +8 -0
  65. package/playbooks/capabilities/laravel/storage-uploads.md +7 -0
  66. package/playbooks/capabilities/postgresql/architecture.md +5 -0
  67. package/playbooks/capabilities/postgresql/migrations.md +5 -0
  68. package/playbooks/capabilities/postgresql/postgresql.manifest.json +15 -0
  69. package/playbooks/capabilities/postgresql/schema-design.md +7 -0
  70. package/playbooks/capabilities/postgresql/security.md +5 -0
  71. package/playbooks/capabilities/postgresql/testing.md +5 -0
  72. package/playbooks/capabilities/prisma/architecture.md +5 -0
  73. package/playbooks/capabilities/prisma/migrations.md +11 -0
  74. package/playbooks/capabilities/prisma/prisma.manifest.json +14 -0
  75. package/playbooks/capabilities/prisma/runtime.md +5 -0
  76. package/playbooks/capabilities/prisma/schema.md +5 -0
  77. package/playbooks/capabilities/prisma/testing.md +5 -0
  78. package/playbooks/capabilities/supabase/architecture.md +5 -0
  79. package/playbooks/capabilities/supabase/authentication.md +5 -0
  80. package/playbooks/capabilities/supabase/expo.md +16 -0
  81. package/playbooks/capabilities/supabase/migrations.md +7 -0
  82. package/playbooks/capabilities/supabase/nextjs.md +24 -0
  83. package/playbooks/capabilities/supabase/rls.md +7 -0
  84. package/playbooks/capabilities/supabase/supabase.manifest.json +32 -0
  85. package/playbooks/capabilities/supabase/testing.md +5 -0
  86. package/playbooks/capabilities/supabase/vite.md +14 -0
  87. package/playbooks/concerns/axios.md +123 -0
  88. package/playbooks/concerns/next-safe-action.md +66 -0
  89. package/playbooks/concerns/next-themes.md +87 -0
  90. package/playbooks/concerns/nuqs.md +59 -0
  91. package/playbooks/concerns/t3-env.md +48 -0
  92. package/playbooks/concerns/tanstack-query.md +145 -0
  93. package/playbooks/concerns/zod.md +174 -0
  94. package/playbooks/concerns/zustand.md +93 -0
  95. package/playbooks/devops/makefile.manifest.json +10 -0
  96. package/playbooks/devops/makefile.md +556 -0
  97. package/playbooks/devops/pr-template.manifest.json +10 -0
  98. package/playbooks/devops/pr-template.md +106 -0
  99. package/playbooks/platform/laravel-ui/blade/architecture.md +5 -0
  100. package/playbooks/platform/laravel-ui/blade/runtime.md +5 -0
  101. package/playbooks/platform/laravel-ui/blade/security.md +5 -0
  102. package/playbooks/platform/laravel-ui/blade/structure.md +5 -0
  103. package/playbooks/platform/laravel-ui/blade/testing.md +5 -0
  104. package/playbooks/platform/laravel-ui/inertia-react/architecture.md +5 -0
  105. package/playbooks/platform/laravel-ui/inertia-react/runtime.md +5 -0
  106. package/playbooks/platform/laravel-ui/inertia-react/security.md +5 -0
  107. package/playbooks/platform/laravel-ui/inertia-react/structure.md +5 -0
  108. package/playbooks/platform/laravel-ui/inertia-react/testing.md +5 -0
  109. package/playbooks/platform/laravel-ui/livewire/architecture.md +5 -0
  110. package/playbooks/platform/laravel-ui/livewire/runtime.md +5 -0
  111. package/playbooks/platform/laravel-ui/livewire/security.md +5 -0
  112. package/playbooks/platform/laravel-ui/livewire/structure.md +5 -0
  113. package/playbooks/platform/laravel-ui/livewire/testing.md +5 -0
  114. package/playbooks/platform/mobile.manifest.json +17 -0
  115. package/playbooks/platform/mobile.md +15 -0
  116. package/playbooks/platform/web.manifest.json +17 -0
  117. package/playbooks/platform/web.md +17 -0
  118. package/playbooks/stack/expo/architecture.md +27 -0
  119. package/playbooks/stack/expo/runtime.md +14 -0
  120. package/playbooks/stack/expo/security.md +18 -0
  121. package/playbooks/stack/expo/structure.md +26 -0
  122. package/playbooks/stack/expo/testing.md +13 -0
  123. package/playbooks/stack/laravel/architecture.md +34 -0
  124. package/playbooks/stack/laravel/runtime.md +27 -0
  125. package/playbooks/stack/laravel/security.md +23 -0
  126. package/playbooks/stack/laravel/structure.md +29 -0
  127. package/playbooks/stack/laravel/testing.md +22 -0
  128. package/playbooks/stack/laravel-ui.manifest.json +42 -0
  129. package/playbooks/stack/laravel.manifest.json +35 -0
  130. package/playbooks/stack/nextjs/architecture.md +62 -0
  131. package/playbooks/stack/nextjs/runtime.md +31 -0
  132. package/playbooks/stack/nextjs/security.md +32 -0
  133. package/playbooks/stack/nextjs/structure.md +50 -0
  134. package/playbooks/stack/nextjs/testing.md +20 -0
  135. package/playbooks/stack/nextjs.manifest.json +49 -0
  136. package/playbooks/stack/no-frontend.manifest.json +25 -0
  137. package/playbooks/stack/none.manifest.json +21 -0
  138. package/playbooks/stack/react-native.manifest.json +49 -0
  139. package/playbooks/stack/react-vite/architecture.md +33 -0
  140. package/playbooks/stack/react-vite/runtime.md +13 -0
  141. package/playbooks/stack/react-vite/security.md +16 -0
  142. package/playbooks/stack/react-vite/structure.md +23 -0
  143. package/playbooks/stack/react-vite/testing.md +12 -0
  144. package/playbooks/stack/react-vite.manifest.json +46 -0
  145. package/playbooks/stack/springboot/architecture.md +40 -0
  146. package/playbooks/stack/springboot/runtime.md +28 -0
  147. package/playbooks/stack/springboot/security.md +28 -0
  148. package/playbooks/stack/springboot/structure.md +30 -0
  149. package/playbooks/stack/springboot/testing.md +22 -0
  150. package/playbooks/stack/springboot.manifest.json +38 -0
  151. package/playbooks/styling/css-modules-extensions.md +267 -0
  152. package/playbooks/styling/css-modules.manifest.json +11 -0
  153. package/playbooks/styling/native-styles.manifest.json +9 -0
  154. package/playbooks/styling/native-styles.md +29 -0
  155. package/playbooks/styling/tailwind-extensions.md +182 -0
  156. package/playbooks/styling/tailwind.manifest.json +11 -0
  157. package/playbooks/universal/accessibility.manifest.json +11 -0
  158. package/playbooks/universal/accessibility.md +45 -0
  159. package/playbooks/universal/coding-rules.manifest.json +12 -0
  160. package/playbooks/universal/coding-rules.md +281 -0
  161. package/playbooks/universal/error-handling.manifest.json +10 -0
  162. package/playbooks/universal/error-handling.md +21 -0
  163. package/playbooks/universal/git-conventions.manifest.json +10 -0
  164. package/playbooks/universal/git-conventions.md +186 -0
  165. package/playbooks/universal/observability.manifest.json +10 -0
  166. package/playbooks/universal/observability.md +29 -0
  167. package/playbooks/universal/security.manifest.json +11 -0
  168. package/playbooks/universal/security.md +30 -0
  169. package/playbooks/universal/typescript.manifest.json +11 -0
  170. package/playbooks/universal/typescript.md +272 -0
  171. package/scripts/compatibility-matrix.mjs +48 -0
  172. package/scripts/validate-content.mjs +76 -0
  173. package/scripts/verify-generated.mjs +153 -0
  174. package/templates/agents/nextjs.md +47 -0
  175. package/templates/agents/react-native.md +48 -0
  176. package/templates/agents/react-vite.md +48 -0
  177. package/templates/docker/compose/postgres.yml +29 -0
  178. package/templates/docker/compose/springboot.yml +69 -0
  179. package/templates/docker/compose/supabase.yml +18 -0
  180. package/templates/docker/compose-prod/springboot.yml +64 -0
  181. package/templates/docker/dockerfile/laravel-inertia.dev.dockerfile +21 -0
  182. package/templates/docker/dockerfile/laravel.dev.dockerfile +12 -0
  183. package/templates/docker/dockerfile/laravel.prod.dockerfile +13 -0
  184. package/templates/docker/dockerfile/nextjs.dev.dockerfile +6 -0
  185. package/templates/docker/dockerfile/nextjs.prod.dockerfile +18 -0
  186. package/templates/docker/dockerfile/springboot.dev.dockerfile +5 -0
  187. package/templates/docker/dockerfile/springboot.prod.dockerfile +10 -0
  188. package/templates/docker/dockerfile/vite.dev.dockerfile +6 -0
  189. package/templates/docker/dockerfile/vite.prod.dockerfile +12 -0
  190. package/templates/gitignore/base.gitignore +32 -0
  191. package/templates/gitignore/nextjs.gitignore +40 -0
  192. package/templates/gitignore/react-native.gitignore +43 -0
  193. package/templates/gitignore/react-vite.gitignore +39 -0
  194. package/templates/makefile/frontend.mk +31 -0
  195. package/templates/makefile/laravel.mk +47 -0
  196. package/templates/makefile/postgres.mk +40 -0
  197. package/templates/makefile/springboot.mk +125 -0
  198. package/templates/makefile/supabase.mk +42 -0
@@ -0,0 +1,172 @@
1
+ import fs from 'fs-extra'
2
+ import path from 'path'
3
+
4
+ /**
5
+ * Extract section headings from a playbook markdown file.
6
+ * Skips fenced code blocks so `#` inside code fences never pollute the index.
7
+ */
8
+ export function extractSections(content) {
9
+ const sections = []
10
+ let inFence = false
11
+ let lineNo = 0
12
+
13
+ for (const line of content.split('\n')) {
14
+ lineNo++
15
+ if (/^\s*```/.test(line)) { inFence = !inFence; continue }
16
+ if (inFence) continue
17
+
18
+ const h1 = /^# (?!#)(.+)$/.exec(line)
19
+ const h2 = /^## (?!#)(.+)$/.exec(line)
20
+ if (!h1 && !h2) continue
21
+
22
+ const title = (h1 ? h1[1] : h2[1]).trim()
23
+ const numbered = /^(\d+)\.\s+(.+)$/.exec(title)
24
+ const ref = numbered ? `§ ${numbered[1]} ${numbered[2]}` : title
25
+ sections.push({ level: h1 ? 1 : 2, title, ref, line: lineNo })
26
+ }
27
+
28
+ return sections
29
+ }
30
+
31
+ /**
32
+ * Resolve a playbook relative path to an absolute path.
33
+ * Handles nested stack facets and concern playbooks transparently.
34
+ */
35
+ export async function resolvePlaybook(playbooksDir, file) {
36
+ return path.join(playbooksDir, file)
37
+ }
38
+
39
+ /**
40
+ * Collect all unique playbook files referenced by this stack's concerns —
41
+ * including concern files (concerns/*.md) and stack files (stack/*.md).
42
+ */
43
+ export function collectPlaybookFiles(stack) {
44
+ const files = new Set(stack.playbooks)
45
+ for (const c of stack.concerns) {
46
+ const pb = c.playbook || c._playbook
47
+ if (pb) files.add(pb)
48
+ }
49
+ return [...files]
50
+ }
51
+
52
+ // Build the § ref rows for a single concern entry
53
+ async function concernRows(concern, playbooksDir) {
54
+ const playbookFile = concern.playbook || concern._playbook
55
+ if (!playbookFile) {
56
+ return [`| \`${concern.id}\` | <!-- MISSING playbook --> | — |`]
57
+ }
58
+
59
+ const fullPath = await resolvePlaybook(playbooksDir, playbookFile)
60
+ let content
61
+ try {
62
+ content = await fs.readFile(fullPath, 'utf-8')
63
+ } catch {
64
+ return [`| \`${concern.id}\` | <!-- MISSING ${playbookFile} --> | — |`]
65
+ }
66
+
67
+ const sections = extractSections(content)
68
+ const wanted = concern.sections || []
69
+
70
+ if (!wanted.length) {
71
+ // No sections declared — just link the playbook
72
+ return [`| \`${concern.id}\` | \`playbooks/${playbookFile}\` | — |`]
73
+ }
74
+
75
+ const normalize = (title) => title
76
+ .replace(/^\d+\.\s+/, '')
77
+ .trim()
78
+ .toLocaleLowerCase('en')
79
+ const matched = sections.filter((section) => {
80
+ const actual = normalize(section.title)
81
+ return wanted.some((title) => {
82
+ const requested = normalize(title)
83
+ return actual === requested || actual.startsWith(`${requested} —`) || actual.startsWith(`${requested} (`)
84
+ })
85
+ })
86
+ if (!matched.length) {
87
+ return [`| \`${concern.id}\` | \`playbooks/${playbookFile}\` | (section not found) |`]
88
+ }
89
+
90
+ return matched.map((s) => `| \`${concern.id}\` | \`playbooks/${playbookFile}\` | ${s.ref} |`)
91
+ }
92
+
93
+ /**
94
+ * Build RULES.md — the lazy index that maps every concern to its playbook §.
95
+ * Agents read only the § they need, never the whole playbook.
96
+ */
97
+ export async function buildRulesIndex(stack, catalog, playbooksDir) {
98
+ const lines = []
99
+
100
+ lines.push('# RULES.md')
101
+ lines.push('')
102
+ lines.push(`**Stack:** ${stack.label}`)
103
+ lines.push(`**Platform:** ${stack.platform}`)
104
+ lines.push('')
105
+ lines.push('> This file is a **lazy index** — `concern → playbook §`.')
106
+ lines.push('> Read only the § you need. Never load all playbooks eagerly.')
107
+ lines.push('> Detail lives in `playbooks/`. Concern files live in `playbooks/concerns/`.')
108
+ lines.push('')
109
+ lines.push('---')
110
+ lines.push('')
111
+
112
+ // Deduplicate concerns by id — required wins over optional
113
+ const seen = new Map()
114
+ for (const c of stack.concerns) {
115
+ if (!seen.has(c.id) || c.required) seen.set(c.id, c)
116
+ }
117
+ const concerns = [...seen.values()]
118
+
119
+ const required = concerns.filter((c) => c.required)
120
+ const optional = concerns.filter((c) => !c.required)
121
+
122
+ // ── Always-on Invariants ───────────────────────────────────────────────
123
+ lines.push('## Always-on Invariants')
124
+ lines.push('')
125
+ lines.push('| Concern | Playbook | Section |')
126
+ lines.push('|---------|----------|---------|')
127
+ for (const c of required) {
128
+ for (const row of await concernRows(c, playbooksDir)) lines.push(row)
129
+ }
130
+ lines.push('')
131
+ lines.push('---')
132
+ lines.push('')
133
+
134
+ // ── Optional Concerns ─────────────────────────────────────────────────
135
+ lines.push('## Optional Concerns')
136
+ lines.push('')
137
+ lines.push('| Concern | Playbook | Section | When |')
138
+ lines.push('|---------|----------|---------|------|')
139
+ for (const c of optional) {
140
+ const rows = await concernRows(c, playbooksDir)
141
+ for (const row of rows) {
142
+ lines.push(row.replace(/ \|$/, ` | ${c.when || '—'} |`))
143
+ }
144
+ }
145
+ lines.push('')
146
+ lines.push('---')
147
+ lines.push('')
148
+ lines.push('**How to use this file:**')
149
+ lines.push('1. Identify which concern your task touches.')
150
+ lines.push('2. Open only the listed playbook at the listed §.')
151
+ lines.push('3. Stop reading when the § ends.')
152
+ lines.push('4. Never read all playbooks eagerly — your context window is finite.')
153
+ lines.push('')
154
+
155
+ return `${lines.join('\n')}\n`
156
+ }
157
+
158
+ /**
159
+ * Copy all stack playbooks AND concern playbooks into the generated project.
160
+ * Preserves the relative path so RULES.md refs stay valid.
161
+ */
162
+ export async function copySelectedPlaybooks(playbooksDir, dest, stack) {
163
+ const allFiles = collectPlaybookFiles(stack)
164
+ for (const file of allFiles) {
165
+ const src = path.join(playbooksDir, file)
166
+ if (await fs.pathExists(src)) {
167
+ const dst = path.join(dest, 'playbooks', file)
168
+ await fs.ensureDir(path.dirname(dst))
169
+ await fs.copy(src, dst)
170
+ }
171
+ }
172
+ }
@@ -0,0 +1,18 @@
1
+ import path from 'node:path'
2
+
3
+ export function isInsideDirectory(candidate, parent) {
4
+ const relative = path.relative(path.resolve(parent), path.resolve(candidate))
5
+ return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative))
6
+ }
7
+
8
+ export function projectLocationNotice({ cwd, cliRoot, projectName }) {
9
+ if (!isInsideDirectory(cwd, cliRoot)) return null
10
+
11
+ const generatedPath = path.join(path.resolve(cwd), projectName)
12
+ const suggestedPath = path.join(path.dirname(path.resolve(cliRoot)), projectName)
13
+ return {
14
+ generatedPath,
15
+ suggestedPath,
16
+ message: `This project was created inside the create-win-project repository. Move or cut the generated folder to your normal projects folder outside this repository before you start committing application work.`,
17
+ }
18
+ }