@dyrected/core 2.5.24 → 2.5.26

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 (169) hide show
  1. package/dist/__tests__/app.test.d.ts +2 -0
  2. package/dist/__tests__/app.test.d.ts.map +1 -0
  3. package/dist/__tests__/app.test.js +27 -0
  4. package/dist/__tests__/app.test.js.map +1 -0
  5. package/dist/__tests__/config.test.d.ts +2 -0
  6. package/dist/__tests__/config.test.d.ts.map +1 -0
  7. package/dist/__tests__/config.test.js +34 -0
  8. package/dist/__tests__/config.test.js.map +1 -0
  9. package/dist/__tests__/deleteMany.test.d.ts +2 -0
  10. package/dist/__tests__/deleteMany.test.d.ts.map +1 -0
  11. package/dist/__tests__/deleteMany.test.js +75 -0
  12. package/dist/__tests__/deleteMany.test.js.map +1 -0
  13. package/dist/__tests__/depth.test.d.ts +2 -0
  14. package/dist/__tests__/depth.test.d.ts.map +1 -0
  15. package/dist/__tests__/depth.test.js +81 -0
  16. package/dist/__tests__/depth.test.js.map +1 -0
  17. package/dist/__tests__/dynamic-options.test.d.ts +2 -0
  18. package/dist/__tests__/dynamic-options.test.d.ts.map +1 -0
  19. package/dist/__tests__/dynamic-options.test.js +132 -0
  20. package/dist/__tests__/dynamic-options.test.js.map +1 -0
  21. package/dist/__tests__/field-inference.test-types.d.ts +24 -0
  22. package/dist/__tests__/field-inference.test-types.d.ts.map +1 -0
  23. package/dist/__tests__/field-inference.test-types.js +87 -0
  24. package/dist/__tests__/field-inference.test-types.js.map +1 -0
  25. package/dist/__tests__/hooks.test.d.ts +2 -0
  26. package/dist/__tests__/hooks.test.d.ts.map +1 -0
  27. package/dist/__tests__/hooks.test.js +320 -0
  28. package/dist/__tests__/hooks.test.js.map +1 -0
  29. package/dist/__tests__/mocks.d.ts +68 -0
  30. package/dist/__tests__/mocks.d.ts.map +1 -0
  31. package/dist/__tests__/mocks.js +151 -0
  32. package/dist/__tests__/mocks.js.map +1 -0
  33. package/dist/__tests__/router.test.d.ts +2 -0
  34. package/dist/__tests__/router.test.d.ts.map +1 -0
  35. package/dist/__tests__/router.test.js +48 -0
  36. package/dist/__tests__/router.test.js.map +1 -0
  37. package/dist/__tests__/where.test.d.ts +2 -0
  38. package/dist/__tests__/where.test.d.ts.map +1 -0
  39. package/dist/__tests__/where.test.js +97 -0
  40. package/dist/__tests__/where.test.js.map +1 -0
  41. package/dist/app-BOrsS7Tz.d.cts +1771 -0
  42. package/dist/app-BOrsS7Tz.d.ts +1771 -0
  43. package/dist/app-BibuoHQG.d.cts +1764 -0
  44. package/dist/app-BibuoHQG.d.ts +1764 -0
  45. package/dist/app-aW2FMuYM.d.cts +1759 -0
  46. package/dist/app-aW2FMuYM.d.ts +1759 -0
  47. package/dist/app.d.ts +21 -0
  48. package/dist/app.d.ts.map +1 -0
  49. package/dist/app.js +56 -0
  50. package/dist/app.js.map +1 -0
  51. package/dist/auth/jexl.d.ts +10 -0
  52. package/dist/auth/jexl.d.ts.map +1 -0
  53. package/dist/auth/jexl.js +22 -0
  54. package/dist/auth/jexl.js.map +1 -0
  55. package/dist/auth/password.d.ts +10 -0
  56. package/dist/auth/password.d.ts.map +1 -0
  57. package/dist/auth/password.js +28 -0
  58. package/dist/auth/password.js.map +1 -0
  59. package/dist/auth/token.d.ts +20 -0
  60. package/dist/auth/token.d.ts.map +1 -0
  61. package/dist/auth/token.js +40 -0
  62. package/dist/auth/token.js.map +1 -0
  63. package/dist/chunk-4EDMZAM5.js +2692 -0
  64. package/dist/chunk-FDQYPPG3.js +2698 -0
  65. package/dist/chunk-NKDX67AW.js +2698 -0
  66. package/dist/chunk-SUGK7UYL.js +311 -0
  67. package/dist/chunk-ZFAOBRHT.js +2709 -0
  68. package/dist/controllers/auth.controller.d.ts +125 -0
  69. package/dist/controllers/auth.controller.d.ts.map +1 -0
  70. package/dist/controllers/auth.controller.js +323 -0
  71. package/dist/controllers/auth.controller.js.map +1 -0
  72. package/dist/controllers/collection.controller.d.ts +88 -0
  73. package/dist/controllers/collection.controller.d.ts.map +1 -0
  74. package/dist/controllers/collection.controller.js +554 -0
  75. package/dist/controllers/collection.controller.js.map +1 -0
  76. package/dist/controllers/global.controller.d.ts +17 -0
  77. package/dist/controllers/global.controller.d.ts.map +1 -0
  78. package/dist/controllers/global.controller.js +116 -0
  79. package/dist/controllers/global.controller.js.map +1 -0
  80. package/dist/controllers/media.controller.d.ts +36 -0
  81. package/dist/controllers/media.controller.d.ts.map +1 -0
  82. package/dist/controllers/media.controller.js +155 -0
  83. package/dist/controllers/media.controller.js.map +1 -0
  84. package/dist/controllers/preview.controller.d.ts +37 -0
  85. package/dist/controllers/preview.controller.d.ts.map +1 -0
  86. package/dist/controllers/preview.controller.js +48 -0
  87. package/dist/controllers/preview.controller.js.map +1 -0
  88. package/dist/index-Bp7PDOYG.d.cts +1750 -0
  89. package/dist/index-Bp7PDOYG.d.ts +1750 -0
  90. package/dist/index-DfAmTZXk.d.cts +1749 -0
  91. package/dist/index-DfAmTZXk.d.ts +1749 -0
  92. package/dist/index.cjs +19 -2324
  93. package/dist/index.d.cts +5 -6
  94. package/dist/index.d.ts +5 -6
  95. package/dist/index.d.ts.map +1 -0
  96. package/dist/index.js +3 -5
  97. package/dist/index.js.map +1 -0
  98. package/dist/middleware/auth.d.ts +18 -0
  99. package/dist/middleware/auth.d.ts.map +1 -0
  100. package/dist/middleware/auth.js +45 -0
  101. package/dist/middleware/auth.js.map +1 -0
  102. package/dist/router.d.ts +8 -0
  103. package/dist/router.d.ts.map +1 -0
  104. package/dist/router.js +463 -0
  105. package/dist/router.js.map +1 -0
  106. package/dist/server.cjs +237 -45
  107. package/dist/server.d.cts +22 -4
  108. package/dist/server.d.ts +22 -4
  109. package/dist/server.d.ts.map +1 -0
  110. package/dist/server.js +2429 -8
  111. package/dist/server.js.map +1 -0
  112. package/dist/services/audit.service.d.ts +23 -0
  113. package/dist/services/audit.service.d.ts.map +1 -0
  114. package/dist/services/audit.service.js +28 -0
  115. package/dist/services/audit.service.js.map +1 -0
  116. package/dist/services/defaults.service.d.ts +8 -0
  117. package/dist/services/defaults.service.d.ts.map +1 -0
  118. package/dist/services/defaults.service.js +55 -0
  119. package/dist/services/defaults.service.js.map +1 -0
  120. package/dist/services/email.service.d.ts +33 -0
  121. package/dist/services/email.service.d.ts.map +1 -0
  122. package/dist/services/email.service.js +219 -0
  123. package/dist/services/email.service.js.map +1 -0
  124. package/dist/services/media.service.d.ts +20 -0
  125. package/dist/services/media.service.d.ts.map +1 -0
  126. package/dist/services/media.service.js +49 -0
  127. package/dist/services/media.service.js.map +1 -0
  128. package/dist/services/population.service.d.ts +20 -0
  129. package/dist/services/population.service.d.ts.map +1 -0
  130. package/dist/services/population.service.js +168 -0
  131. package/dist/services/population.service.js.map +1 -0
  132. package/dist/types/index.d.ts +1749 -0
  133. package/dist/types/index.d.ts.map +1 -0
  134. package/dist/types/index.js +3 -0
  135. package/dist/types/index.js.map +1 -0
  136. package/dist/utils/config.d.ts +8 -0
  137. package/dist/utils/config.d.ts.map +1 -0
  138. package/dist/utils/config.js +153 -0
  139. package/dist/utils/config.js.map +1 -0
  140. package/dist/utils/hooks.d.ts +41 -0
  141. package/dist/utils/hooks.d.ts.map +1 -0
  142. package/dist/utils/hooks.js +169 -0
  143. package/dist/utils/hooks.js.map +1 -0
  144. package/dist/utils/openapi.d.ts +6 -0
  145. package/dist/utils/openapi.d.ts.map +1 -0
  146. package/dist/utils/openapi.js +331 -0
  147. package/dist/utils/openapi.js.map +1 -0
  148. package/dist/utils/parse-where.d.ts +63 -0
  149. package/dist/utils/parse-where.d.ts.map +1 -0
  150. package/dist/utils/parse-where.js +196 -0
  151. package/dist/utils/parse-where.js.map +1 -0
  152. package/dist/utils/readonly-db.d.ts +9 -0
  153. package/dist/utils/readonly-db.d.ts.map +1 -0
  154. package/dist/utils/readonly-db.js +21 -0
  155. package/dist/utils/readonly-db.js.map +1 -0
  156. package/dist/utils/setup-prompt.d.ts +11 -0
  157. package/dist/utils/setup-prompt.d.ts.map +1 -0
  158. package/dist/utils/setup-prompt.js +863 -0
  159. package/dist/utils/setup-prompt.js.map +1 -0
  160. package/dist/utils/swagger.d.ts +5 -0
  161. package/dist/utils/swagger.d.ts.map +1 -0
  162. package/dist/utils/swagger.js +51 -0
  163. package/dist/utils/swagger.js.map +1 -0
  164. package/dist/utils/where-sanitizer.d.ts +10 -0
  165. package/dist/utils/where-sanitizer.d.ts.map +1 -0
  166. package/dist/utils/where-sanitizer.js +63 -0
  167. package/dist/utils/where-sanitizer.js.map +1 -0
  168. package/dist/where-sanitizer-DQIWTQZW.js +50 -0
  169. package/package.json +1 -1
@@ -0,0 +1,863 @@
1
+ // ─────────────────────────────────────────────
2
+ // Section builders
3
+ // ─────────────────────────────────────────────
4
+ function buildEnvironmentSection(frameworkLabel, isSelfHosted, config) {
5
+ const credentialLines = isSelfHosted ? "" : `- Site ID : ${config.siteId}\n- API Key : ${config.apiKey}`;
6
+ return `
7
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
8
+ 1. ENVIRONMENT
9
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
10
+ - Framework : ${frameworkLabel || "Detect it"}
11
+ - Host Type : ${isSelfHosted ? "Self-Hosted (Local/Private Server)" : "Managed (Dyrected Cloud)"}
12
+ - API Base : ${config.baseUrl || "http://localhost:3000"}
13
+ ${credentialLines}`;
14
+ }
15
+ function buildDiagnosticSection() {
16
+ return `
17
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
18
+ 2. PHASE 0 — DISCOVERY
19
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
20
+ Before writing any code, you MUST ask the user these questions.
21
+ Write them exactly as shown below — in plain language with examples.
22
+ Wait for the user to answer ALL of them before proceeding.
23
+
24
+ ─── QUESTION 1 ───
25
+ Ask:
26
+ "Do you already have a website built, or are we starting fresh?
27
+
28
+ → Already built: share your project or describe what pages you have
29
+ (e.g. Home, About, Services, Contact)
30
+ → Starting fresh: just say 'new site' and describe what the site is for"
31
+
32
+ ─── QUESTION 2 ───
33
+ Ask:
34
+ "What kind of content will your client need to update regularly?
35
+
36
+ Here are some examples to help you think:
37
+ → Blog posts or news articles
38
+ → Team member profiles (name, photo, bio)
39
+ → Services or product descriptions
40
+ → Testimonials or reviews
41
+ → Event listings
42
+ → FAQs
43
+ → Homepage text (headline, hero image, call-to-action button)
44
+
45
+ Just list the ones that apply. You can say things like:
46
+ 'They need to update blog posts and team members'"
47
+
48
+ ─── QUESTION 3 ───
49
+ Ask:
50
+ "Are there any pages on the site that should NEVER change — like a
51
+ custom-coded page you want to leave exactly as it is?
52
+
53
+ Example answer: 'The homepage has a custom animation, leave that alone.
54
+ Everything else can be managed from the CMS.'
55
+
56
+ If everything should be manageable, just say 'all pages'"
57
+
58
+ ─── QUESTION 4 ───
59
+ Ask:
60
+ "What is this website for? Pick the closest description:
61
+
62
+ A) A business or agency marketing site (show services, get leads)
63
+ B) A blog or content site (publish articles regularly)
64
+ C) A SaaS or product site (landing page, pricing, features)
65
+ D) A portfolio (show work, case studies)
66
+ E) An e-commerce or product catalogue
67
+ F) Something else — describe it in one sentence"
68
+
69
+ ─── IF EXISTING SITE ───
70
+ If the user confirms they have an existing site, also:
71
+ - Scan the codebase for all hardcoded text that should be CMS-managed
72
+ - Identify repeated data structures that should become collections
73
+ - Propose saving current content to a migration/ folder as .json files
74
+ BEFORE touching any code
75
+ - Report your findings to the user and get confirmation before proceeding
76
+
77
+ Do NOT write any implementation code until all questions are answered
78
+ and the user has confirmed the content plan.`;
79
+ }
80
+ function buildConstraintsSection() {
81
+ return `
82
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
83
+ 3. ARCHITECTURE & CONSTRAINTS
84
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
85
+ - API ACCESS : Use client.collection(slug) as the only entry point.
86
+ - ZERO-STATE : Always use initialData in all data fetches so the site
87
+ renders correctly on first load and never throws during render.
88
+ - MARKETING FREEDOM : Use a dynamic pages collection with a catch-all route
89
+ so marketing can create and manage pages without a developer.
90
+ - BLOCKS DESIGN : Use blocks for flexible page builders. Store as
91
+ [{ blockType: 'slug', ...fields }] and switch on blockType
92
+ in the frontend renderer.
93
+ - DATA SAFETY : Never overwrite or drop existing content or pages.
94
+ Preserve everything before making changes.
95
+ - RESILIENCE : If Dyrected backend is unreachable, fall back to
96
+ initialData and show stale content — never an error page.
97
+ All relationship fields must handle null gracefully.
98
+ Every block renderer must have a default fallback case.
99
+ - AUTO-SEEDING : Use initialData: [...] in CollectionConfig or GlobalConfig
100
+ to automatically populate the database on first run.
101
+ This is great for demo content or default settings.`;
102
+ }
103
+ function buildSchemaRulesSection() {
104
+ return `
105
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
106
+ 4. SCHEMA EVOLUTION RULES
107
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
108
+ - Never drop existing fields from the schema. Mark unused fields as deprecated only.
109
+ - All new fields must have a defaultValue.
110
+ - Use renameTo: 'oldName' to lazily migrate data when renaming fields.
111
+ - Use promoted: true for fields that need high-performance SQL indexing or unique constraints.
112
+ - For Cloud deployments, run npx @dyrected/cli sync:schema after every config change. Self-hosted deployments sync automatically on startup.
113
+ `;
114
+ }
115
+ function buildDoNotSection() {
116
+ return `
117
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
118
+ 5. DO NOT
119
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
120
+ - Do NOT use client.collections — always use client.collection(slug).
121
+ - Do NOT add custom auth middleware to the admin route.
122
+ Dyrected handles admin authentication internally. Do not wrap,
123
+ protect, or redirect the admin route yourself.
124
+ - Do NOT use renderAdminUI in a Nuxt.js project. Use the DyrectedAdmin
125
+ component which is auto-imported by @dyrected/nuxt.
126
+ - Do NOT modify or overwrite existing pages without first preserving their data.
127
+ - Do NOT drop, rename, or remove fields from an existing schema.
128
+ - Do NOT integrate blog posts or testimonials unless explicitly requested.
129
+ - Do NOT skip the diagnostic or discovery phase.`;
130
+ }
131
+ function buildTechnicalReferenceSection() {
132
+ return `
133
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
134
+ 6. TECHNICAL REFERENCE
135
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
136
+ Use defineCollection, defineGlobal, and defineConfig from '@dyrected/core'.
137
+
138
+ FIELD TYPES:
139
+ - Primitive : text | textarea | richText | number | boolean | date | email | url | json | image
140
+ - Choice : select | multiSelect (requires options: [{ label, value }])
141
+ - Structural : array | object (requires nested fields: [...])
142
+ - Relation : relationship (requires relationTo: '<slug>')
143
+ - Media : relationship to an upload collection (e.g. 'media')
144
+ - Blocks : blocks (requires blocks: [{ slug, labels, fields }])
145
+
146
+ COLLECTION OPTIONS:
147
+ - upload: true — media library with file upload support
148
+ - auth: true — adds login/me endpoints; password field is auto-managed
149
+ - audit: true — enables activity logging
150
+ - admin.useAsTitle — field used as display title in admin list view
151
+ - admin.group — groups collection under a sidebar heading
152
+ - admin.hidden — hides collection from the sidebar (internal/system use)
153
+
154
+ FIELD OPTIONS:
155
+ - label — user-friendly display name (REQUIRED for all fields)
156
+ - required — validation
157
+ - unique — database-level uniqueness constraint
158
+ - hasMany — allow multiple values (for relationship, select, image)
159
+ - defaultValue — fallback value (required on all new fields added to existing schemas)
160
+ - promoted — extracts field to a real SQL column for native indexing (SQL adapters only)
161
+ - renameTo — name of the old field key to migrate data from (lazy migration)
162
+ - admin.condition — Jexl expression string to conditionally show/hide field
163
+ e.g. "status == \\"published\\""
164
+ - admin.readOnly — display only, not editable
165
+ - admin.hidden — hidden from editor UI entirely
166
+ - hooks.beforeChange — [async (value) => newValue] transform before save
167
+ - hooks.afterRead — [async (value) => newValue] transform after read
168
+
169
+ GLOBALS:
170
+ Use defineGlobal for single-instance documents like site settings or navigation.
171
+ Access via client.global(slug).get() and client.global(slug).update(data).
172
+
173
+ BLOCKS:
174
+ Blocks are stored as [{ blockType: '<slug>', ...fields }].
175
+ The admin renders a drag-and-drop block editor automatically.
176
+ On the frontend, iterate the array and switch on block.blockType.
177
+ Always include a default case in your switch for unknown block types.
178
+
179
+ COMPLETE SCHEMA EXAMPLE:
180
+ \`\`\`ts
181
+ import { defineCollection, defineGlobal, defineConfig } from '@dyrected/core'
182
+ import { SqliteAdapter } from '@dyrected/db-sqlite'
183
+
184
+ const media = defineCollection({
185
+ slug: 'media',
186
+ upload: true,
187
+ fields: [
188
+ { name: 'alt', label: 'Alt Text', type: 'text' },
189
+ ],
190
+ })
191
+
192
+ const pages = defineCollection({
193
+ slug: 'pages',
194
+ admin: { useAsTitle: 'title', group: 'Content' },
195
+ fields: [
196
+ { name: 'title', label: 'Title', type: 'text', required: true },
197
+ { name: 'slug', label: 'URL Slug', type: 'text', required: true, unique: true },
198
+ { name: 'seo', label: 'SEO Metadata', type: 'object', fields: [
199
+ { name: 'metaTitle', label: 'Meta Title', type: 'text' },
200
+ { name: 'metaDescription', label: 'Meta Description', type: 'textarea' },
201
+ { name: 'ogImage', label: 'OG Image', type: 'relationship', relationTo: 'media' },
202
+ ]},
203
+ {
204
+ name: 'layout',
205
+ label: 'Page Layout',
206
+ type: 'blocks',
207
+ blocks: [
208
+ {
209
+ slug: 'hero',
210
+ labels: { singular: 'Hero', plural: 'Heroes' },
211
+ fields: [
212
+ { name: 'heading', label: 'Heading', type: 'text', required: true },
213
+ { name: 'subheading', label: 'Subheading', type: 'textarea' },
214
+ { name: 'image', label: 'Hero Image', type: 'relationship', relationTo: 'media' },
215
+ { name: 'ctaLabel', label: 'Button Label', type: 'text' },
216
+ { name: 'ctaLink', label: 'Button Link', type: 'url' },
217
+ ],
218
+ },
219
+ {
220
+ slug: 'richContent',
221
+ labels: { singular: 'Rich Content', plural: 'Rich Content Blocks' },
222
+ fields: [
223
+ { name: 'content', label: 'Content', type: 'richText', required: true },
224
+ ],
225
+ },
226
+ {
227
+ slug: 'callToAction',
228
+ labels: { singular: 'Call to Action', plural: 'Calls to Action' },
229
+ fields: [
230
+ { name: 'heading', label: 'Heading', type: 'text', required: true },
231
+ { name: 'description', label: 'Description', type: 'textarea' },
232
+ { name: 'buttonLabel', label: 'Button Text', type: 'text' },
233
+ { name: 'buttonLink', label: 'Button Link', type: 'url' },
234
+ { name: 'theme', label: 'Theme', type: 'select', options: [
235
+ { label: 'Primary', value: 'primary' },
236
+ { label: 'Secondary', value: 'secondary' },
237
+ { label: 'Dark', value: 'dark' },
238
+ ]},
239
+ ],
240
+ },
241
+ ],
242
+ },
243
+ ],
244
+ })
245
+
246
+ const settings = defineGlobal({
247
+ slug: 'settings',
248
+ label: 'Site Settings',
249
+ fields: [
250
+ { name: 'siteName', label: 'Site Name', type: 'text' },
251
+ { name: 'tagline', label: 'Site Tagline', type: 'text' },
252
+ { name: 'logo', label: 'Site Logo', type: 'relationship', relationTo: 'media' },
253
+ { name: 'footerText', label: 'Footer Text', type: 'textarea' },
254
+ ],
255
+ })
256
+
257
+ export default defineConfig({
258
+ collections: [media, pages],
259
+ globals: [settings],
260
+ // Use SqliteAdapter for local, PostgresAdapter or MySqlAdapter for production
261
+ db: new SqliteAdapter({ filename: './dyrected.db' }),
262
+ })
263
+ \`\`\``;
264
+ }
265
+ function buildDeliverablesSection() {
266
+ return `
267
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
268
+ 7. REQUIRED DELIVERABLES — IN THIS ORDER
269
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
270
+ Return your response in exactly this order. Do not combine steps. Do not skip steps.
271
+
272
+ 1. Diagnostic findings (what exists, what needs to become CMS-managed)
273
+ 2. dyrected.config.ts — complete file
274
+ 3. Admin route file — complete file
275
+ 4. Catch-all frontend page route — complete file
276
+ 5. Block components — names and fields only
277
+ 6. Migration/fallback strategy — numbered steps
278
+ 7. Schema sync command
279
+
280
+ API Reference: https://docs.dyrected.com
281
+ If you are unsure about any syntax or property, refer to the documentation above.`;
282
+ }
283
+ // ─────────────────────────────────────────────
284
+ // Framework-specific implementation sections
285
+ // ─────────────────────────────────────────────
286
+ function buildFrameworkSection(activeTab, isSelfHosted, config) {
287
+ const envPrefix = activeTab === "next" ? "NEXT_PUBLIC_" : activeTab === "nuxt" ? "NUXT_PUBLIC_" : "";
288
+ const credentialEnvLines = isSelfHosted
289
+ ? ""
290
+ : `
291
+ apiKey: process.env.${envPrefix}DYRECTED_API_KEY || '${config.apiKey}',
292
+ siteId: process.env.${envPrefix}SITE_ID || '${config.siteId}',`;
293
+ const baseUrlLine = `process.env.${envPrefix}DYRECTED_URL || '${config.baseUrl || "http://localhost:3000"}'`;
294
+ const sections = {
295
+ next: `
296
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
297
+ 8. IMPLEMENTATION — Next.js
298
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
299
+ 1. SDK Setup (lib/dyrected.ts):
300
+ \`\`\`ts
301
+ import { createClient } from '@dyrected/sdk'
302
+
303
+ export const dyrected = createClient({
304
+ baseUrl: ${baseUrlLine},${credentialEnvLines}
305
+ })
306
+ \`\`\`
307
+
308
+ 2. Admin Route (app/cms/page.tsx):
309
+ \`\`\`tsx
310
+ import { DyrectedAdmin } from '@dyrected/next/admin'
311
+
312
+ export default function AdminPage() {
313
+ // DyrectedAdmin handles routing, auth, and CSS automatically.
314
+ // Do NOT wrap this in custom auth middleware.
315
+ return <DyrectedAdmin basename="/cms" />
316
+ }
317
+ \`\`\`
318
+
319
+ 3. Catch-all Page Route (app/[...slug]/page.tsx):
320
+ \`\`\`tsx
321
+ import { dyrected } from '@/lib/dyrected'
322
+
323
+ export default async function CmsPage({ params }: { params: { slug: string[] } }) {
324
+ const slug = params.slug?.join('/') || 'home'
325
+ const page = await dyrected.collection('pages').findOne({ where: { slug: { equals: slug } } })
326
+
327
+ if (!page) return <div>Page not found</div>
328
+
329
+ return (
330
+ <main>
331
+ {page.layout?.map((block: any, i: number) => (
332
+ <BlockRenderer key={i} block={block} />
333
+ ))}
334
+ </main>
335
+ )
336
+ }
337
+ \`\`\``,
338
+ nuxt: `
339
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
340
+ 8. IMPLEMENTATION — Nuxt.js
341
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
342
+ 1. Nuxt.js Config (nuxt.config.ts):
343
+ \`\`\`ts
344
+ export default defineNuxtConfig({
345
+ modules: ['@dyrected/nuxt'],
346
+ dyrected: {
347
+ baseUrl: process.env.${envPrefix}DYRECTED_URL || '${config.baseUrl || "http://localhost:3000"}',${isSelfHosted
348
+ ? ""
349
+ : `
350
+ apiKey: process.env.${envPrefix}DYRECTED_API_KEY || '${config.apiKey}',
351
+ siteId: process.env.${envPrefix}SITE_ID || '${config.siteId}',`}
352
+ },
353
+ })
354
+ \`\`\`
355
+
356
+ 2. Admin Route (pages/cms/index.vue):
357
+ \`\`\`vue
358
+ <script setup lang="ts">
359
+ // DyrectedAdmin is auto-imported by @dyrected/nuxt.
360
+ // Do NOT manually import it.
361
+ // Do NOT use renderAdminUI here.
362
+ // Do NOT add custom auth middleware — Dyrected handles authentication.
363
+ definePageMeta({ layout: false })
364
+ </script>
365
+
366
+ <template>
367
+ <ClientOnly>
368
+ <DyrectedAdmin basename="/cms" />
369
+ </ClientOnly>
370
+ </template>
371
+ \`\`\`
372
+
373
+ 3. Catch-all Page Route (pages/[...slug].vue):
374
+ \`\`\`vue
375
+ <script setup lang="ts">
376
+ const route = useRoute()
377
+ const slug = computed(() =>
378
+ Array.isArray(route.params.slug)
379
+ ? route.params.slug.join('/')
380
+ : route.params.slug || 'home'
381
+ )
382
+
383
+ const { data: page } = await useDyrected('pages').findOne({
384
+ where: { slug: { equals: slug.value } },
385
+ initialData: null,
386
+ })
387
+ </script>
388
+
389
+ <template>
390
+ <main v-if="page">
391
+ <BlockRenderer
392
+ v-for="(block, i) in page.layout"
393
+ :key="i"
394
+ :block="block"
395
+ />
396
+ </main>
397
+ <div v-else>Page not found</div>
398
+ </template>
399
+ \`\`\``,
400
+ react: `
401
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
402
+ 8. IMPLEMENTATION — React
403
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
404
+ 1. SDK Setup (lib/dyrected.ts):
405
+ \`\`\`ts
406
+ import { createClient } from '@dyrected/sdk'
407
+
408
+ export const dyrected = createClient({
409
+ baseUrl: '${config.baseUrl || "https://api.dyrected.cloud"}',${isSelfHosted
410
+ ? ""
411
+ : `
412
+ apiKey: '${config.apiKey}',
413
+ siteId: '${config.siteId}',`}
414
+ })
415
+ \`\`\`
416
+
417
+ 2. Admin Route (pages/cms.tsx):
418
+ \`\`\`tsx
419
+ import { AdminUI } from '@dyrected/admin'
420
+ import '@dyrected/admin/styles'
421
+
422
+ export default function AdminPage() {
423
+ return (
424
+ <div style={{ height: '100vh' }}>
425
+ <AdminUI
426
+ baseUrl="${config.baseUrl || "https://api.dyrected.cloud"}"${isSelfHosted
427
+ ? ""
428
+ : `
429
+ apiKey="${config.apiKey}"
430
+ siteId="${config.siteId}"`}
431
+ />
432
+ </div>
433
+ )
434
+ }
435
+ \`\`\``,
436
+ vue: `
437
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
438
+ 8. IMPLEMENTATION — Vue
439
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
440
+ 1. SDK Setup (lib/dyrected.ts):
441
+ \`\`\`ts
442
+ import { createClient } from '@dyrected/sdk'
443
+
444
+ export const dyrected = createClient({
445
+ baseUrl: '${config.baseUrl || "https://api.dyrected.cloud"}',${isSelfHosted
446
+ ? ""
447
+ : `
448
+ apiKey: '${config.apiKey}',
449
+ siteId: '${config.siteId}',`}
450
+ })
451
+ \`\`\`
452
+
453
+ 2. Admin Route (pages/cms.vue):
454
+ \`\`\`vue
455
+ <template>
456
+ <div ref="container" style="height: 100vh" />
457
+ </template>
458
+
459
+ <script setup>
460
+ import { ref, onMounted, onUnmounted } from 'vue'
461
+ import { renderAdminUI } from '@dyrected/admin'
462
+ import '@dyrected/admin/styles'
463
+
464
+ const container = ref(null)
465
+ let cleanup: (() => void) | undefined
466
+
467
+ onMounted(() => {
468
+ cleanup = renderAdminUI(container.value, {
469
+ baseUrl: '${config.baseUrl || "https://api.dyrected.cloud"}',${isSelfHosted
470
+ ? ""
471
+ : `
472
+ apiKey: '${config.apiKey}',
473
+ siteId: '${config.siteId}',`}
474
+ })
475
+ })
476
+
477
+ onUnmounted(() => cleanup?.())
478
+ </script>
479
+ \`\`\``,
480
+ };
481
+ return sections[activeTab] || sections.next;
482
+ }
483
+ // ─────────────────────────────────────────────
484
+ // Fresh install prompt (no Dyrected installed yet)
485
+ // ─────────────────────────────────────────────
486
+ export function generateFreshSetupPrompt(activeTab, config) {
487
+ const frameworkLabel = activeTab === "next"
488
+ ? "Next.js"
489
+ : activeTab === "nuxt"
490
+ ? "Nuxt.js"
491
+ : activeTab
492
+ ? activeTab.charAt(0).toUpperCase() + activeTab.slice(1)
493
+ : "the project's detected framework";
494
+ const isSelfHosted = config.isSelfHosted === true || (!config.apiKey && !config.siteId);
495
+ const frameworkSetup = {
496
+ nuxt: `
497
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
498
+ 3. INSTALLATION STEPS — Run these in order
499
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
500
+ Tell the user to follow these steps exactly. Explain each one in plain
501
+ language before showing the command. Do not skip any step.
502
+
503
+ STEP 1 — Initialize Dyrected
504
+ Tell the user:
505
+ "Run this command in your terminal inside your Nuxt.js project folder.
506
+ It will set everything up for you automatically."
507
+
508
+ \`\`\`bash
509
+ npx @dyrected/cli init
510
+ \`\`\`
511
+
512
+ When it asks questions, tell the user to:
513
+ - Choose: Nuxt.js 3
514
+ - Choose: SQLite (easiest option, no extra setup needed)
515
+
516
+ The CLI will automatically:
517
+ - Install all required packages
518
+ - Create a dyrected.config.ts file
519
+ - Mount the Admin UI at pages/cms/index.vue
520
+ - Generate a .env.example file
521
+
522
+ STEP 2 — Register the module
523
+ Tell the user to open nuxt.config.ts and add '@dyrected/nuxt' to modules:
524
+
525
+ \`\`\`ts
526
+ export default defineNuxtConfig({
527
+ modules: ['@dyrected/nuxt'],
528
+ })
529
+ \`\`\`
530
+
531
+ STEP 3 — Set up environment variables
532
+ Tell the user:
533
+ "Find the file called .env.example in your project.
534
+ Make a copy of it and rename the copy to .env
535
+ Then open .env and fill in the values."
536
+
537
+ STEP 4 — Start the project
538
+ \`\`\`bash
539
+ pnpm dev
540
+ \`\`\`
541
+
542
+ STEP 5 — Open the dashboard
543
+ Tell the user to open their browser and go to:
544
+ http://localhost:3000/cms
545
+
546
+ If they see the Dyrected admin dashboard, the installation worked.
547
+ Tell them: "You are ready. Now let's set up your content."`,
548
+ next: `
549
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
550
+ 3. INSTALLATION STEPS — Run these in order
551
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
552
+ Tell the user to follow these steps exactly. Explain each one in plain
553
+ language before showing the command. Do not skip any step.
554
+
555
+ STEP 1 — Initialize Dyrected
556
+ Tell the user:
557
+ "Run this command in your terminal inside your Next.js project folder."
558
+
559
+ \`\`\`bash
560
+ npx @dyrected/cli init
561
+ \`\`\`
562
+
563
+ When it asks questions, tell the user to:
564
+ - Choose: Next.js
565
+ - Choose: SQLite (easiest option, no extra setup needed)
566
+
567
+ The CLI will automatically:
568
+ - Install all required packages
569
+ - Create a dyrected.config.ts file
570
+ - Mount the Admin UI at app/cms/page.tsx
571
+ - Generate a .env.example file
572
+
573
+ STEP 2 — Set up environment variables
574
+ Tell the user:
575
+ "Find the file called .env.example in your project.
576
+ Make a copy of it and rename the copy to .env.local
577
+ Then open .env.local and fill in the values."
578
+
579
+ STEP 3 — Start the project
580
+ \`\`\`bash
581
+ pnpm dev
582
+ \`\`\`
583
+
584
+ STEP 4 — Open the dashboard
585
+ Tell the user to open their browser and go to:
586
+ http://localhost:3000/cms
587
+
588
+ If they see the Dyrected admin dashboard, the installation worked.
589
+ Tell them: "You are ready. Now let's set up your content."`,
590
+ react: `
591
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
592
+ 3. INSTALLATION STEPS — Run these in order
593
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
594
+ STEP 1 — Install the SDK and admin packages
595
+ \`\`\`bash
596
+ npm install @dyrected/sdk @dyrected/admin
597
+ \`\`\`
598
+
599
+ STEP 2 — Set up the client (lib/dyrected.ts):
600
+ \`\`\`ts
601
+ import { createClient } from '@dyrected/sdk'
602
+
603
+ export const dyrected = createClient({
604
+ baseUrl: '${config.baseUrl || "https://api.dyrected.cloud"}',${isSelfHosted
605
+ ? ""
606
+ : `
607
+ apiKey: '${config.apiKey}',
608
+ siteId: '${config.siteId}',`}
609
+ })
610
+ \`\`\`
611
+
612
+ STEP 3 — Mount the Admin UI (pages/cms.tsx):
613
+ \`\`\`tsx
614
+ import { AdminUI } from '@dyrected/admin'
615
+ import '@dyrected/admin/styles'
616
+
617
+ export default function AdminPage() {
618
+ return (
619
+ <div style={{ height: '100vh' }}>
620
+ <AdminUI
621
+ baseUrl="${config.baseUrl || "https://api.dyrected.cloud"}"${isSelfHosted
622
+ ? ""
623
+ : `
624
+ apiKey="${config.apiKey}"
625
+ siteId="${config.siteId}"`}
626
+ />
627
+ </div>
628
+ )
629
+ }
630
+ \`\`\``,
631
+ vue: `
632
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
633
+ 3. INSTALLATION STEPS — Run these in order
634
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
635
+ STEP 1 — Install the SDK and admin packages
636
+ \`\`\`bash
637
+ npm install @dyrected/sdk @dyrected/admin
638
+ \`\`\`
639
+
640
+ STEP 2 — Set up the client (lib/dyrected.ts):
641
+ \`\`\`ts
642
+ import { createClient } from '@dyrected/sdk'
643
+
644
+ export const dyrected = createClient({
645
+ baseUrl: '${config.baseUrl || "https://api.dyrected.cloud"}',${isSelfHosted
646
+ ? ""
647
+ : `
648
+ apiKey: '${config.apiKey}',
649
+ siteId: '${config.siteId}',`}
650
+ })
651
+ \`\`\`
652
+
653
+ STEP 3 — Mount the Admin UI (pages/cms.vue):
654
+ \`\`\`vue
655
+ <template>
656
+ <div ref="container" style="height: 100vh" />
657
+ </template>
658
+
659
+ <script setup>
660
+ import { ref, onMounted, onUnmounted } from 'vue'
661
+ import { renderAdminUI } from '@dyrected/admin'
662
+ import '@dyrected/admin/styles'
663
+
664
+ const container = ref(null)
665
+ let cleanup
666
+
667
+ onMounted(() => {
668
+ cleanup = renderAdminUI(container.value, {
669
+ baseUrl: '${config.baseUrl || "https://api.dyrected.cloud"}',${isSelfHosted
670
+ ? ""
671
+ : `
672
+ apiKey: '${config.apiKey}',
673
+ siteId: '${config.siteId}',`}
674
+ })
675
+ })
676
+
677
+ onUnmounted(() => cleanup?.())
678
+ </script>
679
+ \`\`\``,
680
+ };
681
+ return [
682
+ `You are a friendly technical assistant helping someone set up Dyrected CMS for the very first time in a ${frameworkLabel} project. They have NOT installed anything yet.
683
+
684
+ Your job is to:
685
+ 1. Understand who you are talking to before giving any instructions
686
+ 2. Ask simple questions about their project and content needs
687
+ 3. Walk them through setup in a way that matches their technical level
688
+ 4. Confirm each step worked before moving to the next
689
+ 5. Help them design their content so their client can manage it
690
+
691
+ Speak in plain language at all times. Never assume technical knowledge.
692
+ Never show more than one step at a time.
693
+ Never mention the terminal, command line, or any commands until you have
694
+ confirmed the user is comfortable running them.`,
695
+ `
696
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
697
+ 1. ENVIRONMENT
698
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
699
+ - Framework : ${frameworkLabel}
700
+ - Host Type : ${isSelfHosted ? "Self-Hosted" : "Dyrected Cloud"}
701
+ - API Base : ${config.baseUrl || "http://localhost:3000"}
702
+ ${isSelfHosted ? "" : `- Site ID : ${config.siteId}\n- API Key : ${config.apiKey}`}`.trim(),
703
+ `
704
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
705
+ 2. PHASE 0 — UNDERSTAND THE USER FIRST
706
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
707
+ Ask these questions one at a time. Wait for each answer before asking the next.
708
+ Never ask more than one question at a time.
709
+
710
+ ─── QUESTION 1 — TECH LEVEL ───
711
+ This is the most important question. Ask it first.
712
+
713
+ Ask exactly this:
714
+ "Before we dive in — how would you describe yourself?
715
+
716
+ A) I write code myself (I'm comfortable with the terminal and editing files)
717
+ B) I use tools like Lovable, Bolt, or v0 to build with AI — I don't write much code myself
718
+ C) I'm a designer or project manager — someone else usually handles the technical stuff
719
+ D) Something else — just describe how you work"
720
+
721
+ Use their answer to decide how to guide them for the rest of the setup:
722
+ - If A → they are TECHNICAL. You may show terminal commands and code directly.
723
+ - If B → they are SEMI-TECHNICAL. Explain what each step does before showing
724
+ any code or commands. Ask before running anything in the terminal.
725
+ For Lovable users specifically: guide them to use the built-in
726
+ terminal or ask them to paste code into the right file in their editor.
727
+ - If C → they are NON-TECHNICAL. Do not show terminal commands at all.
728
+ Generate all the code and config for them. Walk them through
729
+ copy-pasting into specific files by name. If a terminal step is
730
+ unavoidable, warn them first and offer to write the exact command
731
+ with a clear explanation of what it does and where to run it.
732
+ - If D → ask one follow-up question to understand their workflow before
733
+ deciding which path above fits best.
734
+
735
+ ─── QUESTION 2 — PROJECT STATUS ───
736
+ Ask after Q1 is answered:
737
+
738
+ "Do you already have a ${frameworkLabel} project open,
739
+ or are we starting from scratch?
740
+
741
+ → Already have a project: tell me what the site is about or
742
+ share the folder name
743
+ → Starting fresh: just say 'new project' and I will help you
744
+ create one first"
745
+
746
+ ─── QUESTION 3 — SITE PURPOSE ───
747
+ Ask after Q2 is answered:
748
+
749
+ "What kind of website is this?
750
+
751
+ A) A business or agency site (show services, get enquiries)
752
+ B) A blog or news site (publish articles regularly)
753
+ C) A SaaS or product landing page (features, pricing, sign up)
754
+ D) A portfolio (show work and past projects)
755
+ E) Something else — describe it in one sentence"
756
+
757
+ ─── QUESTION 4 — CONTENT NEEDS ───
758
+ Ask after Q3 is answered:
759
+
760
+ "What will your client need to update themselves — without calling you?
761
+
762
+ Some examples to help you think:
763
+ → Blog posts or news articles
764
+ → Team member profiles (name, photo, bio)
765
+ → Services or product descriptions
766
+ → Homepage text (headline, buttons, images)
767
+ → Testimonials or reviews
768
+ → FAQs
769
+ → Event listings or announcements
770
+
771
+ Just list the ones that apply. Or say 'not sure yet'
772
+ and we will figure it out together."
773
+
774
+ ─── AFTER ALL QUESTIONS ───
775
+ Once all four questions are answered:
776
+ 1. Summarise what you understood in plain English
777
+ 2. Ask the user to confirm before touching any code
778
+ 3. Then move to the installation steps using the correct path
779
+ for their tech level from Question 1`,
780
+ frameworkSetup[activeTab] || frameworkSetup.nuxt,
781
+ `
782
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
783
+ 4. AFTER INSTALLATION — CONTENT SETUP
784
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
785
+ Once the dashboard is confirmed working, help the user design their
786
+ content model in dyrected.config.ts based on what they told you in
787
+ Phase 0.
788
+
789
+ RULES for this phase:
790
+ - Use defineCollection and defineConfig from '@dyrected/core'
791
+ - Use client.collection(slug) only — never client.collections
792
+ - Always use initialData in all data fetches
793
+ - Use a catch-all pages collection for marketing-managed pages
794
+ - Use blocks for flexible page layouts
795
+ - Use type: 'relationship', relationTo: 'collectionSlug' for relations
796
+ - Never throw during render — fall back to initialData on errors
797
+ - All relationship fields must handle null gracefully
798
+
799
+ CONTENT SETUP DELIVERABLES — in this order:
800
+ 1. dyrected.config.ts — complete file based on their answers
801
+ 2. Catch-all page route for CMS-managed pages
802
+ 3. Block components list (names and fields only)
803
+ 4. One example fetch showing how to load content on a page
804
+
805
+ After delivering the config, tell the user to sync their schema.
806
+ For TECHNICAL users show the command directly:
807
+ \`\`\`bash
808
+ npx @dyrected/cli sync:schema
809
+ \`\`\`
810
+ For SEMI-TECHNICAL or NON-TECHNICAL users explain it first:
811
+ "This next step tells Dyrected to read your content setup file
812
+ and prepare the database. Here is the command to run:" then show it.
813
+
814
+ Then ask: "Do you want me to help you connect this content to your
815
+ frontend pages now?"
816
+
817
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
818
+ DO NOT
819
+ ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
820
+ - Do NOT show terminal commands before confirming the user's tech level
821
+ - Do NOT assume the user knows what a terminal, CLI, or package manager is
822
+ - Do NOT show all steps at once — one step at a time always
823
+ - Do NOT use client.collections — use client.collection(slug)
824
+ - Do NOT add custom auth middleware to the admin route
825
+ - Do NOT use renderAdminUI in a Nuxt.js project
826
+ - Do NOT skip the confirmation after each installation step
827
+ - Do NOT use jargon without explaining it in plain English first
828
+ - Do NOT assume the installation worked — ask the user to confirm
829
+
830
+ API Reference: https://docs.dyrected.com
831
+ If you are unsure about any syntax, refer to the official documentation above.`,
832
+ ].join("\n");
833
+ }
834
+ // ─────────────────────────────────────────────
835
+ // Main export
836
+ // ─────────────────────────────────────────────
837
+ export function generateAIPrompt(activeTab, config) {
838
+ const frameworkLabel = activeTab === "next"
839
+ ? "Next.js"
840
+ : activeTab === "nuxt"
841
+ ? "Nuxt.js"
842
+ : activeTab
843
+ ? activeTab.charAt(0).toUpperCase() + activeTab.slice(1)
844
+ : "the project's detected framework";
845
+ const isSelfHosted = config.isSelfHosted === true || (!config.apiKey && !config.siteId);
846
+ const existingSite = config.existingSite ?? false;
847
+ const missionText = existingSite
848
+ ? `You are a Senior Content Architect. Your mission is to integrate Dyrected CMS into an EXISTING ${frameworkLabel} project. Your absolute priority is DATA PRESERVATION and MIGRATION of existing hardcoded content into a flexible, blocks-based schema that empowers marketing teams to move independently.`
849
+ : `You are a Senior Content Architect. Your mission is to integrate Dyrected CMS into a NEW ${frameworkLabel} project. Your priority is DATA PRESERVATION and creating a CMS that empowers marketing teams to move independently without raising tickets to engineering.`;
850
+ const sections = [
851
+ missionText,
852
+ buildEnvironmentSection(frameworkLabel, isSelfHosted, config),
853
+ buildDiagnosticSection(),
854
+ buildConstraintsSection(),
855
+ buildSchemaRulesSection(),
856
+ buildDoNotSection(),
857
+ buildTechnicalReferenceSection(),
858
+ buildDeliverablesSection(),
859
+ buildFrameworkSection(activeTab, isSelfHosted, config),
860
+ ];
861
+ return sections.join("\n");
862
+ }
863
+ //# sourceMappingURL=setup-prompt.js.map