create-thally-docs 0.9.0 → 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.
@@ -1,769 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/customize.ts
4
- import { existsSync, mkdirSync, writeFileSync, readFileSync, readdirSync, cpSync, rmSync } from "fs";
5
- import { dirname, join } from "path";
6
- var MIN_CLI_VERSION = "0.7.0";
7
- var MIN_MCP_VERSION = "0.9.0";
8
- function compareExactVersions(a, b) {
9
- const parse = (value) => /^\d+\.\d+\.\d+$/.test(value) ? value.split(".").map(Number) : null;
10
- const left = parse(a);
11
- const right = parse(b);
12
- if (!left || !right) return null;
13
- for (let i = 0; i < 3; i += 1) {
14
- if (left[i] !== right[i]) return left[i] - right[i];
15
- }
16
- return 0;
17
- }
18
- function raisePinToFloor(current, floor) {
19
- if (!current || current === "*") return floor;
20
- const ordering = compareExactVersions(current, floor);
21
- if (ordering === null) return current;
22
- return ordering < 0 ? floor : current;
23
- }
24
- var STARTER_PAGES = {
25
- "introduction.mdx": `---
26
- title: Introduction
27
- description: Welcome to {NAME}.
28
- mode: home
29
- keywords:
30
- - {NAME}
31
- - documentation
32
- - overview
33
- - getting started
34
- ---
35
-
36
- <Hero
37
- title="Start building with {NAME}"
38
- subtitle="Complete the quickstart, learn the core workflow, then choose the next task that matches your goal."
39
- primaryLabel="Start the quickstart"
40
- primaryHref="/quickstart"
41
- secondaryLabel="Explore components"
42
- secondaryHref="/components"
43
- />
44
-
45
- ## Build your documentation
46
-
47
- Start with the first useful result, then shape the content around your readers.
48
-
49
- <CardGroup cols="2">
50
- <Card title="Complete the quickstart" icon="party-horn" href="/quickstart">
51
- Install {NAME}, complete the smallest useful workflow, and verify the result.
52
- </Card>
53
- <Card title="Create a guide" icon="grid-round" href="/components">
54
- Turn a product task into clear steps using tabs, cards, callouts, and more.
55
- </Card>
56
- <Card title="Integrate the API" icon="code-simple" href="/api">
57
- Find an endpoint, understand its inputs, and make your first request.
58
- </Card>
59
- <Card title="Customize your site" icon="wrench" href="/customization">
60
- Make the navigation, brand, typography, and links your own.
61
- </Card>
62
- </CardGroup>
63
-
64
- ## Publish and extend
65
-
66
- Add another language or make the same documentation available to an AI agent.
67
-
68
- <CardGroup cols="2">
69
- <Card title="Publish another language" icon="message" href="/es">
70
- Use the included Spanish pages as a starting point for localized documentation.
71
- </Card>
72
- <Card title="Connect an AI agent" icon="link-simple" href="/llms.txt">
73
- Give an agent clean, structured context through the generated discovery endpoints.
74
- </Card>
75
- </CardGroup>
76
-
77
- <Note type="info" title="Make it yours">
78
- Start by editing \`src/content/introduction.mdx\`. Then update \`docs.json\` to
79
- organize navigation and \`src/data/site.ts\` to set your product name and links.
80
- </Note>
81
- `,
82
- "quickstart.mdx": `---
83
- title: Get started with {NAME}
84
- description: Install {NAME}, complete the core workflow, and verify your first successful result.
85
- keywords:
86
- - {NAME}
87
- - quickstart
88
- - installation
89
- - getting started
90
- ---
91
-
92
- By the end of this guide, you will install {NAME}, complete its smallest useful
93
- workflow, and verify the result. Keep this path focused on one outcome; move
94
- optional configuration and alternative workflows into separate guides.
95
-
96
- ## Before you begin
97
-
98
- Replace this starter list with the exact requirements a reader needs:
99
-
100
- - An account or credential, if the workflow requires one
101
- - A supported runtime, device, browser, or operating system
102
- - Permission to create or modify the resource used in the example
103
-
104
- <Steps>
105
- <Step title="Install {NAME}">
106
- Give readers one recommended installation path.
107
-
108
- \`\`\`bash
109
- npm install your-package
110
- \`\`\`
111
- </Step>
112
- <Step title="Add the required configuration">
113
- Include only the settings required for this first successful run.
114
-
115
- \`\`\`bash
116
- your-cli init
117
- \`\`\`
118
- </Step>
119
- <Step title="Complete your first task">
120
- Use one realistic example that produces an observable result.
121
-
122
- \`\`\`bash
123
- your-cli start
124
- \`\`\`
125
- </Step>
126
- <Step title="Verify the result">
127
- Tell readers exactly what they should see, where they should see it, and
128
- how to recover if the expected result does not appear.
129
- </Step>
130
- </Steps>
131
-
132
- ## What you accomplished
133
-
134
- Summarize the working state the reader now has in one or two sentences.
135
-
136
- ## Choose your next task
137
-
138
- <CardGroup cols={3}>
139
- <Card title="Create a guide" icon="grid-round" href="/components">
140
- Learn which content components make a task easier to follow.
141
- </Card>
142
- <Card title="Integrate the API" icon="code-simple" href="/api">
143
- Explore endpoints and make a request against your API.
144
- </Card>
145
- <Card title="Customize your site" icon="wrench" href="/customization">
146
- Update navigation, branding, typography, and project links.
147
- </Card>
148
- </CardGroup>
149
- `,
150
- "components.mdx": `---
151
- title: Components
152
- description: A compact tour of the rich MDX components available in {NAME}.
153
- keywords:
154
- - {NAME}
155
- - components
156
- - MDX
157
- ---
158
-
159
- Use components to keep complex instructions clear without turning every page
160
- into a wall of text.
161
-
162
- ## Show equivalent paths
163
-
164
- <Tabs>
165
- <Tab title="npm">
166
- \`\`\`bash
167
- npm install your-package
168
- \`\`\`
169
- </Tab>
170
- <Tab title="pnpm">
171
- \`\`\`bash
172
- pnpm add your-package
173
- \`\`\`
174
- </Tab>
175
- <Tab title="yarn">
176
- \`\`\`bash
177
- yarn add your-package
178
- \`\`\`
179
- </Tab>
180
- </Tabs>
181
-
182
- ## Reveal detail when it matters
183
-
184
- <Accordion title="Where should advanced configuration live?">
185
- Keep the default path visible and move optional detail into an accordion. This
186
- lets new readers move quickly without hiding information from experts.
187
- </Accordion>
188
-
189
- ## Communicate status
190
-
191
- <Badge variant="success">Stable</Badge>{" "}
192
- <Badge variant="warning">Beta</Badge>{" "}
193
- <Badge variant="info">New</Badge>
194
-
195
- <Tip>
196
- Browse the complete component library at [docs.thally.io](https://docs.thally.io/components/card).
197
- </Tip>
198
- `,
199
- "customization.mdx": `---
200
- title: Customization
201
- description: Make {NAME} feel unmistakably like your product.
202
- keywords:
203
- - {NAME}
204
- - branding
205
- - navigation
206
- ---
207
-
208
- Your documentation should feel like part of the product\u2014not a separate website.
209
-
210
- <CardGroup cols="2">
211
- <Card title="Brand and theme" icon="party-horn" href="https://docs.thally.io/guides/branding-and-theming">
212
- Configure colors, logos, favicons, typography, and light or dark presentation.
213
- </Card>
214
- <Card title="Navigation" icon="book-open" href="https://docs.thally.io/guides/configuring-navigation">
215
- Organize tabs, icon-labelled groups, pages, and external destinations in \`docs.json\`.
216
- </Card>
217
- <Card title="Domains" icon="link-simple" href="https://app.thally.io">
218
- Connect a custom domain from your site settings in Thally Cloud.
219
- </Card>
220
- <Card title="Analytics and feedback" icon="message" href="https://app.thally.io">
221
- Learn what readers need and collect feedback without third-party widgets.
222
- </Card>
223
- </CardGroup>
224
-
225
- <Note type="info" title="Start with docs.json">
226
- Navigation and portable presentation settings live in \`docs.json\`. Site
227
- identity and fallback brand values live in \`src/data/site.ts\`.
228
- </Note>
229
- `,
230
- "changelog.mdx": `---
231
- title: Changelog
232
- description: Notable changes, releases, and improvements to {NAME}.
233
- keywords:
234
- - {NAME}
235
- - changelog
236
- - releases
237
- - updates
238
- ---
239
-
240
- ## v0.1.0
241
-
242
- The first release of your **{NAME}** documentation.
243
-
244
- - Initial docs site scaffolded with [Thally](https://github.com/thallylabs/thally)
245
- - Agent-ready endpoints live: \`/llms.txt\`, \`/ai.txt\`, \`/api/docs-index\`, and \`/api/agent-readiness\`
246
- - Starter guides in the Get started tab and an interactive API reference
247
-
248
- Edit this page at \`src/content/changelog.mdx\` to announce your own releases as you ship.
249
- `
250
- };
251
- var STARTER_SPANISH_PAGES = {
252
- "introduction.mdx": `---
253
- title: Introducci\xF3n
254
- description: Te damos la bienvenida a {NAME}.
255
- mode: home
256
- ---
257
-
258
- <Hero
259
- title="Empieza a crear con {NAME}"
260
- subtitle="Completa el inicio r\xE1pido, aprende el flujo principal y elige la siguiente tarea seg\xFAn tu objetivo."
261
- primaryLabel="Empezar el inicio r\xE1pido"
262
- primaryHref="/es/quickstart"
263
- secondaryLabel="Explorar componentes"
264
- secondaryHref="/es/components"
265
- />
266
-
267
- ## Crea tu documentaci\xF3n
268
-
269
- Empieza con el primer resultado \xFAtil y organiza el contenido para tus lectores.
270
-
271
- <CardGroup cols="2">
272
- <Card title="Completa el inicio r\xE1pido" icon="party-horn" href="/es/quickstart">
273
- Instala {NAME}, completa el flujo principal y comprueba el resultado.
274
- </Card>
275
- <Card title="Crea una gu\xEDa" icon="grid-round" href="/es/components">
276
- Convierte una tarea en pasos claros con pesta\xF1as, tarjetas y avisos.
277
- </Card>
278
- <Card title="Integra la API" icon="code-simple" href="/es/api">
279
- Encuentra un endpoint, comprende sus entradas y realiza una solicitud.
280
- </Card>
281
- <Card title="Personaliza el sitio" icon="wrench" href="/es/customization">
282
- Adapta la navegaci\xF3n, marca, tipograf\xEDa y enlaces.
283
- </Card>
284
- </CardGroup>
285
-
286
- ## Publica y ampl\xEDa
287
-
288
- A\xF1ade otro idioma o comparte la misma documentaci\xF3n con un agente de IA.
289
-
290
- <CardGroup cols="2">
291
- <Card title="Publica otro idioma" icon="message" href="/">
292
- Cambia entre ingl\xE9s y espa\xF1ol desde el selector de idioma.
293
- </Card>
294
- <Card title="Conecta un agente de IA" icon="link-simple" href="/llms.txt">
295
- Ofrece contexto estructurado mediante los endpoints de descubrimiento.
296
- </Card>
297
- </CardGroup>
298
- `,
299
- "quickstart.mdx": `---
300
- title: Empieza con {NAME}
301
- description: Instala {NAME}, completa el flujo principal y comprueba tu primer resultado.
302
- ---
303
-
304
- Al terminar esta gu\xEDa, habr\xE1s instalado {NAME}, completado su flujo m\xE1s \xFAtil y
305
- comprobado el resultado.
306
-
307
- ## Antes de empezar
308
-
309
- - Una cuenta o credencial, si el flujo la necesita
310
- - Un entorno, dispositivo o navegador compatible
311
- - Permiso para crear o modificar el recurso del ejemplo
312
-
313
- <Steps>
314
- <Step title="Instala {NAME}">
315
- Muestra una \xFAnica ruta de instalaci\xF3n recomendada.
316
-
317
- \`\`\`bash
318
- npm install your-package
319
- \`\`\`
320
- </Step>
321
- <Step title="A\xF1ade la configuraci\xF3n necesaria">
322
- Incluye solo los ajustes necesarios para completar este flujo.
323
- </Step>
324
- <Step title="Completa tu primera tarea">
325
- Usa un ejemplo realista que produzca un resultado observable.
326
- </Step>
327
- <Step title="Comprueba el resultado">
328
- Explica qu\xE9 debe ver el lector y d\xF3nde debe encontrarlo.
329
- </Step>
330
- </Steps>
331
-
332
- ## Elige tu siguiente tarea
333
-
334
- <CardGroup cols={3}>
335
- <Card title="Crea una gu\xEDa" icon="grid-round" href="/es/components" />
336
- <Card title="Integra la API" icon="code-simple" href="/es/api" />
337
- <Card title="Personaliza el sitio" icon="wrench" href="/es/customization" />
338
- </CardGroup>
339
- `,
340
- "components.mdx": `---
341
- title: Componentes
342
- description: Una muestra de los componentes MDX disponibles en {NAME}.
343
- ---
344
-
345
- <Tabs>
346
- <Tab title="npm">\`npm install your-package\`</Tab>
347
- <Tab title="pnpm">\`pnpm add your-package\`</Tab>
348
- <Tab title="yarn">\`yarn add your-package\`</Tab>
349
- </Tabs>
350
-
351
- <Accordion title="\xBFD\xF3nde debe ir la configuraci\xF3n avanzada?">
352
- Mant\xE9n visible el camino principal y coloca los detalles opcionales aqu\xED.
353
- </Accordion>
354
-
355
- <Badge variant="success">Estable</Badge>{" "}
356
- <Badge variant="warning">Beta</Badge>{" "}
357
- <Badge variant="info">Nuevo</Badge>
358
- `,
359
- "customization.mdx": `---
360
- title: Personalizaci\xF3n
361
- description: Haz que {NAME} se sienta como una parte natural de tu producto.
362
- ---
363
-
364
- <CardGroup cols="2">
365
- <Card title="Marca y tema" icon="party-horn">Configura colores, logotipos, tipograf\xEDa y apariencia.</Card>
366
- <Card title="Navegaci\xF3n" icon="book-open">Organiza pesta\xF1as, grupos con iconos y p\xE1ginas en \`docs.json\`.</Card>
367
- <Card title="Dominios" icon="link-simple">Conecta un dominio personalizado desde Thally Cloud.</Card>
368
- <Card title="Anal\xEDtica y feedback" icon="message">Comprende qu\xE9 necesitan tus lectores.</Card>
369
- </CardGroup>
370
- `,
371
- "changelog.mdx": `---
372
- title: Novedades
373
- description: Cambios, versiones y mejoras destacadas de {NAME}.
374
- ---
375
-
376
- ## v0.1.0
377
-
378
- La primera versi\xF3n de la documentaci\xF3n de **{NAME}**.
379
-
380
- - Sitio creado con [Thally](https://github.com/thallylabs/thally)
381
- - Referencia de API y contenido preparado para agentes
382
- - Ejemplo biling\xFCe en ingl\xE9s y espa\xF1ol
383
- `
384
- };
385
- function buildStarterDocsJson({
386
- enableAiChat,
387
- repoUrl,
388
- i18nLocales
389
- }) {
390
- const config = {};
391
- config.theme = "default";
392
- if (enableAiChat) {
393
- config.ai = { chat: true };
394
- }
395
- if (repoUrl) {
396
- config.navbar = {
397
- links: [{ label: "GitHub", href: repoUrl, type: "github" }],
398
- primary: { label: "Get started", href: "/quickstart" }
399
- };
400
- }
401
- const locales = [
402
- { code: "en", label: "English" },
403
- { code: "es", label: "Espa\xF1ol" },
404
- ...(i18nLocales ?? []).filter(({ code }) => code !== "en" && code !== "es")
405
- ];
406
- config.i18n = { defaultLocale: "en", locales };
407
- config.tabs = [
408
- {
409
- tab: "Get started",
410
- groups: [
411
- { group: "Start here", icon: "book-open", pages: ["introduction", "quickstart"] },
412
- { group: "Create content", icon: "grid-round", pages: ["components"] },
413
- { group: "Customize your site", icon: "wrench", pages: ["customization"] }
414
- ]
415
- },
416
- { tab: "API Reference", api: { source: "openapi.yaml" } },
417
- { tab: "Changelog", href: "/changelog" }
418
- ];
419
- return JSON.stringify(config, null, 2) + "\n";
420
- }
421
- function renderStarterAgentGuide(projectName) {
422
- return `# ${projectName} documentation instructions
423
-
424
- ## About this project
425
-
426
- - This is a documentation site built with [Thally](https://github.com/thallylabs/thally).
427
- - Pages are MDX files with YAML frontmatter in \`src/content/\`.
428
- - Navigation and product features are configured in \`docs.json\`.
429
- - Site identity and fallback brand values live in \`src/data/site.ts\`.
430
- - Use \`/llms.txt\`, \`/llms-full.txt\`, and \`/skill.md\` on the deployed site for agent-readable context.
431
-
432
- ## Terminology
433
-
434
- <!-- Add product-specific terms and preferred usage. -->
435
-
436
- ## Writing style
437
-
438
- - Use active voice and address the reader as \u201Cyou.\u201D
439
- - Keep sentences concise and headings in sentence case.
440
- - Bold interface labels and format commands, files, and code with backticks.
441
- - Lead with the outcome, then explain prerequisites and steps.
442
-
443
- ## Content boundaries
444
-
445
- <!-- Define what belongs in public docs and what must remain internal. -->
446
- `;
447
- }
448
- function renderStarterReadme(projectName) {
449
- return `# ${projectName}
450
-
451
- Documentation powered by [Thally](https://github.com/thallylabs/thally).
452
-
453
- ## Local development
454
-
455
- \`\`\`bash
456
- npm install
457
- npm run dev
458
- \`\`\`
459
-
460
- The server starts at [http://localhost:3040](http://localhost:3040), or the next
461
- available port when 3040 is already in use.
462
-
463
- ## Write your docs
464
-
465
- - Add MDX pages in \`src/content/\`.
466
- - Organize navigation and product features in \`docs.json\`.
467
- - Update the site name, links, and brand defaults in \`src/data/site.ts\`.
468
- - Copy \`.env.example\` to \`.env.local\` for local secrets.
469
-
470
- The starter includes a home hero, icon-grouped navigation, English and Spanish
471
- examples, a guided quickstart, component showcase, changelog, OpenAPI reference,
472
- and \`AGENTS.md\` writing instructions for coding agents.
473
-
474
- ## Publishing changes
475
-
476
- Push changes to the default branch to trigger your connected deployment. If the
477
- site is not connected yet, add the repository in
478
- [Thally Cloud](https://app.thally.io) or deploy it to any Next.js host.
479
-
480
- Run \`npx create-thally-docs check --ci .\` before publishing. Deploy the site
481
- anywhere Next.js is supported, or connect the repository to
482
- [Thally Cloud](https://app.thally.io) for managed hosting and services.
483
- `;
484
- }
485
- function buildStarterFiles({
486
- projectName,
487
- enableAiChat = true,
488
- repoUrl = "",
489
- i18nLocales
490
- }) {
491
- const files = [
492
- {
493
- path: "docs.json",
494
- content: buildStarterDocsJson({
495
- enableAiChat,
496
- repoUrl: repoUrl || void 0,
497
- i18nLocales
498
- })
499
- },
500
- { path: "AGENTS.md", content: renderStarterAgentGuide(projectName) },
501
- { path: "README.md", content: renderStarterReadme(projectName) }
502
- ];
503
- for (const [filename, template] of Object.entries(STARTER_PAGES)) {
504
- files.push({
505
- path: `src/content/${filename}`,
506
- content: template.replace(/\{NAME\}/g, projectName)
507
- });
508
- }
509
- for (const [filename, template] of Object.entries(STARTER_SPANISH_PAGES)) {
510
- files.push({
511
- path: `src/content/es/${filename}`,
512
- content: template.replace(/\{NAME\}/g, projectName)
513
- });
514
- }
515
- return files;
516
- }
517
- function writeStarterContent(targetDir, projectName, enableAiChat = true, repoUrl = "", i18nLocales) {
518
- const contentDir = join(targetDir, "src", "content");
519
- if (existsSync(contentDir)) {
520
- const entries = readdirSync(contentDir);
521
- for (const entry of entries) {
522
- const fullPath = join(contentDir, entry);
523
- rmSync(fullPath, { recursive: true, force: true });
524
- }
525
- } else {
526
- mkdirSync(contentDir, { recursive: true });
527
- }
528
- for (const file of buildStarterFiles({
529
- projectName,
530
- enableAiChat,
531
- repoUrl,
532
- i18nLocales
533
- })) {
534
- if (file.path === "AGENTS.md" || file.path === "README.md") continue;
535
- const targetPath = join(targetDir, file.path);
536
- mkdirSync(dirname(targetPath), { recursive: true });
537
- writeFileSync(targetPath, file.content, "utf8");
538
- }
539
- }
540
- function writeStarterAgentGuide(targetDir, projectName) {
541
- writeFileSync(join(targetDir, "AGENTS.md"), renderStarterAgentGuide(projectName), "utf8");
542
- }
543
- function writeStarterReadme(targetDir, projectName) {
544
- writeFileSync(join(targetDir, "README.md"), renderStarterReadme(projectName), "utf8");
545
- }
546
- function writeCloudflareRuntimeConfig(targetDir, slug) {
547
- writeFileSync(
548
- join(targetDir, "open-next.config.ts"),
549
- `/** OpenNext adapter configuration for the Cloudflare Workers runtime. */
550
- import { defineCloudflareConfig } from '@opennextjs/cloudflare/config'
551
-
552
- export default defineCloudflareConfig()
553
- `,
554
- "utf8"
555
- );
556
- writeFileSync(
557
- join(targetDir, "wrangler.jsonc"),
558
- `${JSON.stringify(
559
- {
560
- $schema: "node_modules/wrangler/config-schema.json",
561
- name: slug,
562
- main: ".open-next/worker.js",
563
- compatibility_date: "2026-07-15",
564
- compatibility_flags: ["nodejs_compat", "global_fetch_strictly_public"],
565
- observability: {
566
- enabled: true,
567
- logs: { head_sampling_rate: 1 },
568
- traces: { enabled: true, head_sampling_rate: 0.01 }
569
- },
570
- assets: {
571
- directory: ".open-next/assets",
572
- binding: "ASSETS"
573
- }
574
- },
575
- null,
576
- 2
577
- )}
578
- `,
579
- "utf8"
580
- );
581
- }
582
- function updateSiteConfig(targetDir, projectName, description, brandPreset, repoUrl) {
583
- const siteFile = join(targetDir, "src", "data", "site.ts");
584
- if (!existsSync(siteFile)) {
585
- console.log(" \u26A0\uFE0F Could not find src/data/site.ts \u2014 skipping config update.");
586
- return;
587
- }
588
- let source = readFileSync(siteFile, "utf8");
589
- source = source.replace(
590
- /name:\s*'[^']*'/,
591
- `name: '${projectName.replace(/'/g, "\\'")}'`
592
- );
593
- source = source.replace(
594
- /description:\s*\n\s*'[^']*'/,
595
- `description:
596
- '${description.replace(/'/g, "\\'")}'`
597
- );
598
- source = source.replace(
599
- /const brandPreset:\s*BrandPresetKey\s*=\s*'[^']*'/,
600
- `const brandPreset: BrandPresetKey = '${brandPreset}'`
601
- );
602
- source = source.replace(/repoUrl:\s*'[^']*'/, `repoUrl: '${repoUrl}'`);
603
- source = source.replace(
604
- /\{\s*label:\s*'GitHub',\s*href:\s*'[^']*'\s*\}/,
605
- `{ label: 'GitHub', href: '${repoUrl}' }`
606
- );
607
- source = source.replace(
608
- /\{\s*label:\s*'Support',\s*href:\s*'[^']*'\s*\}/,
609
- `{ label: 'Support', href: '${repoUrl ? `${repoUrl}/issues/new` : ""}' }`
610
- );
611
- if (!repoUrl) {
612
- source = source.replace(
613
- /\n\s*\{\s*label:\s*'(?:GitHub|Support)',\s*href:\s*''\s*\},?/g,
614
- ""
615
- );
616
- }
617
- writeFileSync(siteFile, source, "utf8");
618
- }
619
- function patchApiReferenceGuard(targetDir) {
620
- const filePath = join(targetDir, "src", "data", "api-reference.ts");
621
- if (!existsSync(filePath)) return;
622
- let source = readFileSync(filePath, "utf8");
623
- source = source.replace(
624
- /export async function buildApiNavigation\([^)]*\)[^{]*\{\n/,
625
- (match) => `${match} if (apiReferenceConfig.specs.length === 0) return []
626
- `
627
- );
628
- writeFileSync(filePath, source, "utf8");
629
- }
630
- function patchTopBarNavigation(targetDir) {
631
- const filePath = join(targetDir, "src", "components", "layout", "top-bar.tsx");
632
- if (!existsSync(filePath)) return;
633
- const source = readFileSync(filePath, "utf8");
634
- if (!source.includes("target={isExternal ? '_blank' : undefined}")) return;
635
- const patched = source.replace(
636
- /if \(collection\.href\) \{\n const isExternal[^\n]+\n return \(\n <a[\s\S]*?<\/a>\n \)\n \}/,
637
- `if (collection.href) {
638
- const isExternal = /^https?:\\/\\//.test(collection.href)
639
- if (isExternal) {
640
- return (
641
- <a
642
- key={collection.id}
643
- href={collection.href}
644
- target="_blank"
645
- rel="noreferrer"
646
- className={baseClasses}
647
- >
648
- {collection.label}
649
- </a>
650
- )
651
- }
652
- return (
653
- <Link
654
- key={collection.id}
655
- href={collection.href}
656
- className={baseClasses}
657
- >
658
- {collection.label}
659
- </Link>
660
- )
661
- }`
662
- );
663
- writeFileSync(filePath, patched, "utf8");
664
- }
665
- function patchOpenApiFetch(targetDir) {
666
- const filePath = join(targetDir, "src", "lib", "openapi", "fetch.ts");
667
- if (!existsSync(filePath)) return;
668
- let source = readFileSync(filePath, "utf8");
669
- source = source.replace(
670
- /const absolutePath = path\.isAbsolute\(filePath\) \? filePath : path\.resolve\(process\.cwd\(\), filePath\)/,
671
- `const absolutePath = filePath.startsWith('/')
672
- ? path.resolve(process.cwd(), 'public', filePath.slice(1))
673
- : path.resolve(process.cwd(), filePath)`
674
- );
675
- writeFileSync(filePath, source, "utf8");
676
- }
677
- function updateEnvExample(targetDir) {
678
- const envFile = join(targetDir, ".env.example");
679
- if (existsSync(envFile)) {
680
- const envLocal = join(targetDir, ".env.local");
681
- if (!existsSync(envLocal)) {
682
- cpSync(envFile, envLocal);
683
- }
684
- }
685
- }
686
- function patchPackageJson(targetDir, slug) {
687
- const pkgPath = join(targetDir, "package.json");
688
- if (!existsSync(pkgPath)) return;
689
- const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
690
- const hadWorkspaces = Array.isArray(pkg.workspaces) && pkg.workspaces.length > 0;
691
- const hasRuntimeSourceCompiler = existsSync(
692
- join(targetDir, "scripts", "build-runtime-sources.mts")
693
- );
694
- pkg.name = slug;
695
- delete pkg.workspaces;
696
- if (pkg.scripts) {
697
- if (hasRuntimeSourceCompiler) {
698
- pkg.scripts["runtime-sources:build"] ??= "tsx scripts/build-runtime-sources.mts";
699
- pkg.scripts["predev"] = "npm run runtime-sources:build";
700
- pkg.scripts["postinstall"] = "npm run runtime-sources:build";
701
- pkg.scripts["prebuild"] = "npm run runtime-sources:build && npm run embeddings:build";
702
- } else {
703
- pkg.scripts["prebuild"] = "npm run embeddings:build";
704
- }
705
- delete pkg.scripts["pretest"];
706
- delete pkg.scripts["packages:build"];
707
- pkg.scripts["build:cloudflare"] = "opennextjs-cloudflare build";
708
- pkg.scripts["preview:cloudflare"] = "npm run build:cloudflare && opennextjs-cloudflare preview";
709
- pkg.scripts["deploy:cloudflare"] = "npm run build:cloudflare && opennextjs-cloudflare deploy";
710
- pkg.scripts["upload:cloudflare"] = "npm run build:cloudflare && opennextjs-cloudflare upload";
711
- }
712
- pkg.devDependencies ??= {};
713
- const cliPin = raisePinToFloor(pkg.devDependencies["@thallylabs/cli"], MIN_CLI_VERSION);
714
- const raisedCliPin = cliPin !== pkg.devDependencies["@thallylabs/cli"];
715
- pkg.devDependencies["@thallylabs/cli"] = cliPin;
716
- pkg.devDependencies["@opennextjs/cloudflare"] ??= "1.15.0";
717
- pkg.devDependencies.vite ??= "7.2.6";
718
- pkg.devDependencies.wrangler ??= "4.111.0";
719
- let raisedMcpPin = false;
720
- if (pkg.dependencies?.["@thallylabs/mcp"]) {
721
- const mcpPin = raisePinToFloor(pkg.dependencies["@thallylabs/mcp"], MIN_MCP_VERSION);
722
- raisedMcpPin = mcpPin !== pkg.dependencies["@thallylabs/mcp"];
723
- pkg.dependencies["@thallylabs/mcp"] = mcpPin;
724
- }
725
- writeFileSync(pkgPath, `${JSON.stringify(pkg, null, 2)}
726
- `, "utf8");
727
- const lockPath = join(targetDir, "package-lock.json");
728
- if (!existsSync(lockPath)) return;
729
- const lock = JSON.parse(readFileSync(lockPath, "utf8"));
730
- const hasWorkspaceEntries = Object.keys(lock.packages ?? {}).some(
731
- (key) => key === "packages" || key.startsWith("packages/")
732
- );
733
- if (hadWorkspaces || hasWorkspaceEntries || raisedCliPin || raisedMcpPin) {
734
- rmSync(lockPath);
735
- return;
736
- }
737
- lock.name = slug;
738
- if (lock.packages?.[""]) lock.packages[""].name = slug;
739
- writeFileSync(lockPath, `${JSON.stringify(lock, null, 2)}
740
- `, "utf8");
741
- }
742
- function patchGitignore(targetDir) {
743
- const gitignorePath = join(targetDir, ".gitignore");
744
- const existing = existsSync(gitignorePath) ? readFileSync(gitignorePath, "utf8") : "";
745
- const lines = existing.split(/\r?\n/);
746
- if (lines.includes("node_modules/")) return;
747
- const separator = existing.length > 0 && !existing.endsWith("\n") ? "\n" : "";
748
- writeFileSync(gitignorePath, `${existing}${separator}node_modules/
749
- `, "utf8");
750
- }
751
-
752
- export {
753
- MIN_CLI_VERSION,
754
- MIN_MCP_VERSION,
755
- raisePinToFloor,
756
- buildStarterDocsJson,
757
- buildStarterFiles,
758
- writeStarterContent,
759
- writeStarterAgentGuide,
760
- writeStarterReadme,
761
- writeCloudflareRuntimeConfig,
762
- updateSiteConfig,
763
- patchApiReferenceGuard,
764
- patchTopBarNavigation,
765
- patchOpenApiFetch,
766
- updateEnvExample,
767
- patchPackageJson,
768
- patchGitignore
769
- };