@dominikcz/greg 0.9.27

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 (183) hide show
  1. package/README.md +397 -0
  2. package/bin/greg.js +241 -0
  3. package/bin/init.js +351 -0
  4. package/bin/templates/docs/getting-started.md +47 -0
  5. package/bin/templates/docs/index.md +11 -0
  6. package/bin/templates/greg.config.js +39 -0
  7. package/bin/templates/greg.config.ts +38 -0
  8. package/bin/templates/index.html +16 -0
  9. package/bin/templates/src/App.svelte +5 -0
  10. package/bin/templates/src/app.css +20 -0
  11. package/bin/templates/src/main.js +9 -0
  12. package/bin/templates/svelte.config.js +1 -0
  13. package/bin/templates/tsconfig.json +21 -0
  14. package/bin/templates/vite.config.js +23 -0
  15. package/docs/__partials/markdown/examples/basic.md +4 -0
  16. package/docs/__partials/markdown/examples/diff.md +10 -0
  17. package/docs/__partials/markdown/examples/focus.md +5 -0
  18. package/docs/__partials/markdown/examples/language-title.md +3 -0
  19. package/docs/__partials/markdown/examples/line-highlighting.md +5 -0
  20. package/docs/__partials/markdown/examples/line-numbers.md +5 -0
  21. package/docs/__partials/note.md +4 -0
  22. package/docs/guide/__shared-warning.md +4 -0
  23. package/docs/guide/asset-handling.md +88 -0
  24. package/docs/guide/deploying.md +162 -0
  25. package/docs/guide/getting-started.md +334 -0
  26. package/docs/guide/index.md +23 -0
  27. package/docs/guide/localization.md +290 -0
  28. package/docs/guide/markdown/code.md +95 -0
  29. package/docs/guide/markdown/components-and-mermaid.md +43 -0
  30. package/docs/guide/markdown/containers.md +110 -0
  31. package/docs/guide/markdown/header-anchors.md +34 -0
  32. package/docs/guide/markdown/includes.md +84 -0
  33. package/docs/guide/markdown/index.md +20 -0
  34. package/docs/guide/markdown/inline-attributes.md +21 -0
  35. package/docs/guide/markdown/links-and-toc.md +64 -0
  36. package/docs/guide/markdown/math.md +54 -0
  37. package/docs/guide/markdown/syntax-highlighting.md +75 -0
  38. package/docs/guide/routing.md +150 -0
  39. package/docs/guide/using-svelte.md +88 -0
  40. package/docs/guide/versioning.md +281 -0
  41. package/docs/incompatibilities.md +48 -0
  42. package/docs/index.md +43 -0
  43. package/docs/reference/badge.md +100 -0
  44. package/docs/reference/carbon-ads.md +46 -0
  45. package/docs/reference/code-group.md +126 -0
  46. package/docs/reference/home-page.md +232 -0
  47. package/docs/reference/index.md +18 -0
  48. package/docs/reference/markdowndocs.md +275 -0
  49. package/docs/reference/outline.md +79 -0
  50. package/docs/reference/search.md +263 -0
  51. package/docs/reference/steps.md +200 -0
  52. package/docs/reference/team-page.md +189 -0
  53. package/docs/reference/theme.md +150 -0
  54. package/fakeDocsGenerator/generate_docs.js +310 -0
  55. package/package.json +92 -0
  56. package/scripts/build-versions.js +609 -0
  57. package/scripts/generate-static.js +79 -0
  58. package/scripts/render-markdown.js +420 -0
  59. package/src/lib/MarkdownDocs/AiChat.svelte +936 -0
  60. package/src/lib/MarkdownDocs/BackToTop.svelte +68 -0
  61. package/src/lib/MarkdownDocs/Breadcrumb.svelte +68 -0
  62. package/src/lib/MarkdownDocs/DocsNavigation.svelte +149 -0
  63. package/src/lib/MarkdownDocs/DocsSiteHeader.svelte +758 -0
  64. package/src/lib/MarkdownDocs/DocsVersionSwitcher.svelte +103 -0
  65. package/src/lib/MarkdownDocs/MarkdownDocs.svelte +2115 -0
  66. package/src/lib/MarkdownDocs/MarkdownRenderer.svelte +487 -0
  67. package/src/lib/MarkdownDocs/Outline.svelte +238 -0
  68. package/src/lib/MarkdownDocs/PrevNext.svelte +115 -0
  69. package/src/lib/MarkdownDocs/SearchModal.svelte +1241 -0
  70. package/src/lib/MarkdownDocs/TreeView.svelte +32 -0
  71. package/src/lib/MarkdownDocs/TreeViewItem.svelte +219 -0
  72. package/src/lib/MarkdownDocs/VersionOutdatedNotice.svelte +72 -0
  73. package/src/lib/MarkdownDocs/__tests__/codeDirectives.test.js +54 -0
  74. package/src/lib/MarkdownDocs/__tests__/common.test.js +41 -0
  75. package/src/lib/MarkdownDocs/__tests__/docsExamplesLint.test.js +77 -0
  76. package/src/lib/MarkdownDocs/__tests__/fixtures/docs/markdown/__partial-basic.md +3 -0
  77. package/src/lib/MarkdownDocs/__tests__/fixtures/docs/markdown/snippet.js +9 -0
  78. package/src/lib/MarkdownDocs/__tests__/fixtures/includes/part.md +11 -0
  79. package/src/lib/MarkdownDocs/__tests__/fixtures/includes/wrapper.md +5 -0
  80. package/src/lib/MarkdownDocs/__tests__/fixtures/snippets/sample.js +8 -0
  81. package/src/lib/MarkdownDocs/__tests__/fixtures/snippets/sample.md +5 -0
  82. package/src/lib/MarkdownDocs/__tests__/helpers.js +67 -0
  83. package/src/lib/MarkdownDocs/__tests__/localeUtils.test.js +204 -0
  84. package/src/lib/MarkdownDocs/__tests__/markdown.test.js +704 -0
  85. package/src/lib/MarkdownDocs/__tests__/markdownRendererRuntime.test.js +65 -0
  86. package/src/lib/MarkdownDocs/__tests__/searchIndexBuilder.test.js +117 -0
  87. package/src/lib/MarkdownDocs/__tests__/sqliteStore.test.js +202 -0
  88. package/src/lib/MarkdownDocs/__tests__/useRouter.test.js +16 -0
  89. package/src/lib/MarkdownDocs/ai/adapters/customAdapter.js +14 -0
  90. package/src/lib/MarkdownDocs/ai/adapters/customAdapter.ts +43 -0
  91. package/src/lib/MarkdownDocs/ai/adapters/ollamaAdapter.js +81 -0
  92. package/src/lib/MarkdownDocs/ai/adapters/ollamaAdapter.ts +116 -0
  93. package/src/lib/MarkdownDocs/ai/adapters/openaiAdapter.js +92 -0
  94. package/src/lib/MarkdownDocs/ai/adapters/openaiAdapter.ts +137 -0
  95. package/src/lib/MarkdownDocs/ai/aiProvider.ts +31 -0
  96. package/src/lib/MarkdownDocs/ai/characters.js +52 -0
  97. package/src/lib/MarkdownDocs/ai/characters.ts +69 -0
  98. package/src/lib/MarkdownDocs/ai/chunkStore.ts +25 -0
  99. package/src/lib/MarkdownDocs/ai/chunker.js +85 -0
  100. package/src/lib/MarkdownDocs/ai/chunker.ts +135 -0
  101. package/src/lib/MarkdownDocs/ai/docLinker.js +26 -0
  102. package/src/lib/MarkdownDocs/ai/docLinker.ts +36 -0
  103. package/src/lib/MarkdownDocs/ai/promptBuilder.js +33 -0
  104. package/src/lib/MarkdownDocs/ai/promptBuilder.ts +53 -0
  105. package/src/lib/MarkdownDocs/ai/ragPipeline.js +54 -0
  106. package/src/lib/MarkdownDocs/ai/ragPipeline.ts +106 -0
  107. package/src/lib/MarkdownDocs/ai/stores/memoryStore.js +88 -0
  108. package/src/lib/MarkdownDocs/ai/stores/memoryStore.ts +112 -0
  109. package/src/lib/MarkdownDocs/ai/stores/sqliteStore.ts +372 -0
  110. package/src/lib/MarkdownDocs/ai/types.ts +71 -0
  111. package/src/lib/MarkdownDocs/aiServer.js +288 -0
  112. package/src/lib/MarkdownDocs/codeDirectives.js +191 -0
  113. package/src/lib/MarkdownDocs/codeFenceInfo.js +45 -0
  114. package/src/lib/MarkdownDocs/codeGroup.ts +46 -0
  115. package/src/lib/MarkdownDocs/common.ts +47 -0
  116. package/src/lib/MarkdownDocs/docsUtils.js +281 -0
  117. package/src/lib/MarkdownDocs/index.plugins.js +22 -0
  118. package/src/lib/MarkdownDocs/layouts/LayoutDoc.svelte +8 -0
  119. package/src/lib/MarkdownDocs/layouts/LayoutHome.svelte +58 -0
  120. package/src/lib/MarkdownDocs/layouts/LayoutPage.svelte +9 -0
  121. package/src/lib/MarkdownDocs/loadGregConfig.js +82 -0
  122. package/src/lib/MarkdownDocs/localeUtils.ts +682 -0
  123. package/src/lib/MarkdownDocs/markdownRendererRuntime.ts +314 -0
  124. package/src/lib/MarkdownDocs/mermaidThemes.js +319 -0
  125. package/src/lib/MarkdownDocs/navigationUtils.js +22 -0
  126. package/src/lib/MarkdownDocs/rehypeCodeGroup.js +326 -0
  127. package/src/lib/MarkdownDocs/rehypeCodeTitle.js +96 -0
  128. package/src/lib/MarkdownDocs/rehypeToc.js +170 -0
  129. package/src/lib/MarkdownDocs/remarkCodeMeta.js +22 -0
  130. package/src/lib/MarkdownDocs/remarkContainers.js +329 -0
  131. package/src/lib/MarkdownDocs/remarkCustomAnchors.js +42 -0
  132. package/src/lib/MarkdownDocs/remarkEscapeSvelte.js +33 -0
  133. package/src/lib/MarkdownDocs/remarkGlobalComponents.js +65 -0
  134. package/src/lib/MarkdownDocs/remarkImports.js +461 -0
  135. package/src/lib/MarkdownDocs/remarkImportsBrowser.js +349 -0
  136. package/src/lib/MarkdownDocs/remarkInlineAttrs.js +95 -0
  137. package/src/lib/MarkdownDocs/remarkMathToHtml.js +138 -0
  138. package/src/lib/MarkdownDocs/searchIndexBuilder.js +497 -0
  139. package/src/lib/MarkdownDocs/searchServer.js +263 -0
  140. package/src/lib/MarkdownDocs/treeViewTypes.ts +11 -0
  141. package/src/lib/MarkdownDocs/useRouter.svelte.ts +114 -0
  142. package/src/lib/MarkdownDocs/useSplitter.svelte.ts +33 -0
  143. package/src/lib/MarkdownDocs/versioningDefaults.js +20 -0
  144. package/src/lib/MarkdownDocs/vitePluginAiServer.js +204 -0
  145. package/src/lib/MarkdownDocs/vitePluginCopyDocs.js +153 -0
  146. package/src/lib/MarkdownDocs/vitePluginFrontmatter.js +109 -0
  147. package/src/lib/MarkdownDocs/vitePluginGregConfig.js +108 -0
  148. package/src/lib/MarkdownDocs/vitePluginSearchIndex.js +57 -0
  149. package/src/lib/MarkdownDocs/vitePluginSearchServer.js +190 -0
  150. package/src/lib/components/Badge.svelte +59 -0
  151. package/src/lib/components/Button.svelte +138 -0
  152. package/src/lib/components/CarbonAds.svelte +99 -0
  153. package/src/lib/components/CodeGroup.svelte +102 -0
  154. package/src/lib/components/Feature.svelte +209 -0
  155. package/src/lib/components/Features.svelte +123 -0
  156. package/src/lib/components/Hero.svelte +399 -0
  157. package/src/lib/components/Image.svelte +128 -0
  158. package/src/lib/components/Link.svelte +105 -0
  159. package/src/lib/components/SocialLink.svelte +84 -0
  160. package/src/lib/components/SocialLinks.svelte +33 -0
  161. package/src/lib/components/Steps.svelte +143 -0
  162. package/src/lib/components/TeamMember.svelte +273 -0
  163. package/src/lib/components/TeamMembers.svelte +81 -0
  164. package/src/lib/components/TeamPage.svelte +65 -0
  165. package/src/lib/components/TeamPageSection.svelte +108 -0
  166. package/src/lib/components/TeamPageTitle.svelte +89 -0
  167. package/src/lib/components/index.js +24 -0
  168. package/src/lib/portal/context.js +12 -0
  169. package/src/lib/portal/index.js +3 -0
  170. package/src/lib/portal/portal.svelte +14 -0
  171. package/src/lib/portal/slot.svelte +8 -0
  172. package/src/lib/scss/__code.scss +128 -0
  173. package/src/lib/scss/__containers.scss +99 -0
  174. package/src/lib/scss/__markdown.scss +447 -0
  175. package/src/lib/scss/__scrollbar.scss +60 -0
  176. package/src/lib/scss/__steps.scss +100 -0
  177. package/src/lib/scss/__theme.scss +238 -0
  178. package/src/lib/scss/__toc.scss +55 -0
  179. package/src/lib/scss/__utilities.scss +7 -0
  180. package/src/lib/scss/greg.scss +9 -0
  181. package/src/lib/spinner/spinner.svelte +42 -0
  182. package/svelte.config.js +146 -0
  183. package/types/index.d.ts +456 -0
package/README.md ADDED
@@ -0,0 +1,397 @@
1
+ # Greg
2
+
3
+ Svelte 5 + Vite-powered documentation engine. Write Markdown, get a beautiful documentation site — hot-reloaded in milliseconds.
4
+
5
+ Inspired by [VitePress](https://vitepress.dev){target="_blank"}, built on Svelte 5.
6
+
7
+ ## Quick start
8
+
9
+ ```sh
10
+ npx @dominikcz/greg init
11
+ ```
12
+
13
+ For unattended/default setup (no prompts):
14
+
15
+ ```sh
16
+ npx @dominikcz/greg init --defaults
17
+ ```
18
+
19
+ The interactive wizard will ask for docs path, site title, TypeScript preference, and the type of initial documentation (empty, sample, or generated fake docs). It can also install all required dependencies for you.
20
+
21
+ At the end you only need:
22
+
23
+ ```sh
24
+ npm run dev
25
+ ```
26
+
27
+ In this repository, prefer `npm run ...` scripts for development.
28
+ In consumer projects using Greg, use `greg ...` (typically via npm scripts) or `npx greg ...`.
29
+
30
+ ## Manual installation
31
+
32
+ ```sh
33
+ npm install --save-dev @dominikcz/greg @sveltejs/vite-plugin-svelte svelte vite
34
+ ```
35
+
36
+ If your `package.json` does not already define module type, set:
37
+
38
+ ```json
39
+ {
40
+ "type": "module"
41
+ }
42
+ ```
43
+
44
+ **`vite.config.js`**
45
+
46
+ ```js
47
+ import { defineConfig } from 'vite'
48
+ import { svelte } from '@sveltejs/vite-plugin-svelte'
49
+ import {
50
+ vitePluginGregConfig,
51
+ vitePluginSearchIndex,
52
+ vitePluginSearchServer,
53
+ vitePluginFrontmatter,
54
+ vitePluginCopyDocs,
55
+ } from '@dominikcz/greg/plugins'
56
+
57
+ export default defineConfig({
58
+ plugins: [
59
+ svelte(),
60
+ vitePluginGregConfig(),
61
+ vitePluginSearchIndex({ docsDir: 'docs', srcDir: '/' }),
62
+ vitePluginSearchServer({ docsDir: 'docs', srcDir: '/' }),
63
+ vitePluginFrontmatter({ docsDir: 'docs', srcDir: '/' }),
64
+ vitePluginCopyDocs({ docsDir: 'docs', srcDir: '/' }),
65
+ ],
66
+ })
67
+ ```
68
+
69
+ **`svelte.config.js`** (must be `.js` — not `.ts`)
70
+
71
+ ```js
72
+ export { default } from '@dominikcz/greg/svelte.config'
73
+ ```
74
+
75
+ **`greg.config.js`** (or `.ts`)
76
+
77
+ ```js
78
+ /** @type {import('@dominikcz/greg').GregConfig} */
79
+ export default {
80
+ srcDir: 'docs',
81
+ docsBase: '',
82
+ mainTitle: 'My Docs',
83
+ sidebar: [
84
+ { text: 'Guide', auto: '/guide' },
85
+ { text: 'GitHub', link: 'https://github.com/dominikcz/greg' }, // default: _self
86
+ { text: 'GitHub (new tab)', link: 'https://github.com/dominikcz/greg', target: '_blank' },
87
+ ],
88
+ }
89
+ ```
90
+
91
+ **`src/App.svelte`**
92
+
93
+ ```svelte
94
+ <script>
95
+ import MarkdownDocs from '@dominikcz/greg'
96
+ </script>
97
+
98
+ <MarkdownDocs />
99
+ ```
100
+
101
+ ## Localization (VitePress-compatible)
102
+
103
+ Greg supports VitePress-style `locales` in `greg.config.js`.
104
+
105
+ - Locale keys use paths like `'/'`, `'/pl/'`, `'/de/'`
106
+ - They are resolved under `docsBase` (URL prefix)
107
+ - Supported per locale: `lang`, `title`, `label`
108
+ - Supported per locale `themeConfig` keys:
109
+ `nav`, `sidebar`, `outline`, `lastUpdatedText`, `langMenuLabel`,
110
+ `sidebarMenuLabel`, `skipToContentLabel`, `returnToTopLabel`,
111
+ `darkModeSwitchLabel`, `lightModeSwitchTitle`, `darkModeSwitchTitle`,
112
+ `docFooter`, `siteTitle`, `logo`, `socialLinks`, `editLink`, `footer`, `aside`, `lastUpdated`
113
+ - Header automatically shows a language switcher when at least two locales are configured
114
+ - `i18nRouting: true` (default) keeps the same relative page when possible
115
+ - `i18nRouting: false` switches directly to locale root
116
+
117
+ ```js
118
+ /** @type {import('@dominikcz/greg').GregConfig} */
119
+ export default {
120
+ srcDir: 'docs',
121
+ docsBase: '',
122
+ i18nRouting: true,
123
+ locales: {
124
+ '/': {
125
+ lang: 'en-US',
126
+ title: 'My Docs',
127
+ themeConfig: {
128
+ nav: [
129
+ { text: 'Guide', link: '/guide' },
130
+ { text: 'Reference', link: '/reference' },
131
+ ],
132
+ sidebar: [
133
+ { text: 'Guide', auto: '/guide' },
134
+ { text: 'Reference', auto: '/reference' },
135
+ ],
136
+ outline: [2, 3],
137
+ lastUpdatedText: 'Last updated:',
138
+ langMenuLabel: 'Change language',
139
+ sidebarMenuLabel: 'Menu',
140
+ skipToContentLabel: 'Skip to content',
141
+ returnToTopLabel: 'Return to top',
142
+ darkModeSwitchLabel: 'Appearance',
143
+ lightModeSwitchTitle: 'Switch to light theme',
144
+ darkModeSwitchTitle: 'Switch to dark theme',
145
+ docFooter: { prev: 'Previous', next: 'Next' },
146
+ },
147
+ },
148
+ '/pl/': {
149
+ lang: 'pl-PL',
150
+ label: 'Polski',
151
+ title: 'Moje Dokumenty',
152
+ themeConfig: {
153
+ nav: [
154
+ { text: 'Przewodnik', link: '/pl/guide' },
155
+ { text: 'Referencja', link: '/pl/reference' },
156
+ ],
157
+ sidebar: [
158
+ { text: 'Przewodnik', auto: '/pl/guide' },
159
+ { text: 'Referencja', auto: '/pl/reference' },
160
+ ],
161
+ outline: { level: [2, 3], label: 'Na tej stronie' },
162
+ lastUpdatedText: 'Zaktualizowano:',
163
+ langMenuLabel: 'Zmien jezyk',
164
+ sidebarMenuLabel: 'Menu',
165
+ skipToContentLabel: 'Przejdz do tresci',
166
+ returnToTopLabel: 'Wroc na gore',
167
+ darkModeSwitchLabel: 'Wyglad',
168
+ lightModeSwitchTitle: 'Przelacz na jasny motyw',
169
+ darkModeSwitchTitle: 'Przelacz na ciemny motyw',
170
+ docFooter: { prev: 'Poprzednia', next: 'Nastepna' },
171
+ },
172
+ },
173
+ },
174
+ }
175
+ ```
176
+
177
+ ## CLI
178
+
179
+ For development in this repository, use `npm run ...` scripts (they call the local CLI entrypoint).
180
+ When Greg is installed in a project, the `greg` command is still available via npm scripts and `npx greg ...`.
181
+
182
+ | Command | Description |
183
+ | --------------------- | ------------------------------------- |
184
+ | `greg init` | Interactive project scaffolding |
185
+ | `greg dev` | Start Vite dev server |
186
+ | `greg build` | Production build (auto versioning) |
187
+ | `greg build:static` | Production build + static export |
188
+ | `greg build:markdown` | Export resolved markdown |
189
+ | `greg preview` | Preview production build |
190
+ | `greg search-server` | Standalone search API server |
191
+
192
+ ## Multi-version Docs
193
+
194
+ Greg supports two source strategies configured under `greg.config.* > versioning`:
195
+
196
+ - `branches` (default): reads docs from configured git branches/refs and caches snapshots/builds per commit SHA
197
+ - `folders`: reads docs directly from version folders in the working tree
198
+
199
+ ### Rules
200
+
201
+ 1. Put all versioning config in `greg.config.js` (or `greg.config.ts`) under `versioning`.
202
+ 2. Choose one strategy in `versioning.strategy`.
203
+ 3. Map each built version id to its source:
204
+ - branch mode: `versioning.branches[]` with `version` + `branch`
205
+ - folder mode: `versioning.folders[]` with `version` + `dir`
206
+ 4. Set `versioning.default` and optional `versioning.aliases` for selector behavior.
207
+
208
+ ### Branch Mode Guide
209
+
210
+ Use this when each docs version should come from a Git branch/ref.
211
+
212
+ What to configure:
213
+
214
+ 1. `versioning.strategy = 'branches'`
215
+ 2. `versioning.branches[]` entries with `version`, `branch`, optional `docsDir`, `title`
216
+ 3. `versioning.default` and optional `versioning.aliases`
217
+
218
+ Example `versioning` value:
219
+
220
+ ```js [greg.config.js]
221
+ export default {
222
+ versioning: {
223
+ strategy: 'branches',
224
+ default: 'latest',
225
+ aliases: {
226
+ latest: '2.1',
227
+ stable: '2.0'
228
+ },
229
+ branches: [
230
+ { version: '2.1', branch: 'main', title: '2.1' },
231
+ { version: '2.0', branch: 'release/2.0', title: '2.0' }
232
+ ]
233
+ }
234
+ }
235
+ ```
236
+
237
+ ### Folder Mode Guide
238
+
239
+ Use this when each docs version should come from a directory in the working tree.
240
+
241
+ What to configure:
242
+
243
+ 1. `versioning.strategy = 'folders'`
244
+ 2. `versioning.folders[]` entries with `version`, `dir`, optional `srcDir`, `title`
245
+ 3. `versioning.default` and optional `versioning.aliases`
246
+
247
+ Example `versioning` value:
248
+
249
+ ```js [greg.config.js]
250
+ export default {
251
+ versioning: {
252
+ strategy: 'folders',
253
+ default: 'latest',
254
+ aliases: {
255
+ latest: '2.1',
256
+ stable: '2.0'
257
+ },
258
+ folders: [
259
+ { version: '2.1', dir: './docs', title: '2.1' },
260
+ { version: '2.0', dir: './versions/2.0/docs', title: '2.0' }
261
+ ]
262
+ }
263
+ }
264
+ ```
265
+
266
+ ### Commands
267
+
268
+ After configuration is in place, run:
269
+
270
+ ```sh
271
+ greg build
272
+ ```
273
+
274
+ Output is generated to `<outDir>/__versions/<version>` (default `dist/__versions/<version>`) and a manifest is written to `<outDir>/__versions/versions.json`.
275
+ After that, Greg syncs the default version to `dist/` so the root output is directly hostable.
276
+
277
+ Defaults are VitePress-compatible:
278
+
279
+ - `outDir` comes from top-level `greg.config.* > outDir` (default `dist`)
280
+ - manifest path prefix is based on top-level `greg.config.* > base` (default `/`)
281
+
282
+ Optional UI labels/messages can be configured under `versioning.ui`:
283
+
284
+ ```js [greg.config.js]
285
+ export default {
286
+ versioning: {
287
+ ui: {
288
+ versionMenuLabel: 'Version',
289
+ manifestUnavailableText: 'Version selector unavailable',
290
+ showManifestUnavailableStatus: false,
291
+ outdatedVersionMessage: 'You are viewing an older version ({current}). Recommended: {default}.',
292
+ outdatedVersionActionLabel: 'Go to latest'
293
+ }
294
+ }
295
+ }
296
+ ```
297
+
298
+ To override those labels per locale, use `versioning.locales`:
299
+
300
+ ```js [greg.config.js]
301
+ export default {
302
+ versioning: {
303
+ locales: {
304
+ '/': {
305
+ ui: {
306
+ versionMenuLabel: 'Version'
307
+ }
308
+ },
309
+ '/pl/': {
310
+ ui: {
311
+ versionMenuLabel: 'Wersja'
312
+ }
313
+ }
314
+ }
315
+ }
316
+ }
317
+ ```
318
+
319
+ Resolution order for versioning UI text is:
320
+
321
+ 1. `versioning.locales[active-locale].ui`
322
+ 2. `versioning.ui`
323
+ 3. built-in default text
324
+
325
+ If `versions.json` cannot be loaded, Greg now shows a subtle fallback text in the header instead of the selector.
326
+
327
+ Example manifest:
328
+
329
+ ```json
330
+ {
331
+ "default": "latest",
332
+ "versions": [
333
+ { "version": "2.1", "title": "2.1", "path": "/__versions/2.1/" },
334
+ { "version": "2.0", "title": "2.0", "path": "/__versions/2.0/" }
335
+ ],
336
+ "aliases": {
337
+ "latest": "2.1",
338
+ "stable": "2.0"
339
+ }
340
+ }
341
+ ```
342
+
343
+ ## Resolved Markdown Export
344
+
345
+ Generate a fully expanded markdown snapshot (all `<!--@include: ...-->` and `<<< ...` resolved)
346
+ for AI knowledge-base ingestion or server-side indexing pipelines.
347
+
348
+ ```sh
349
+ greg build:markdown
350
+ ```
351
+
352
+ Output is written to `dist/resolved-markdown` and mirrors the `docs/` structure.
353
+
354
+ ## TypeScript
355
+
356
+ Greg ships types at `@dominikcz/greg`. `greg.config.ts` is supported — it is transpiled via esbuild at build time.
357
+
358
+ ```ts
359
+ import type { GregConfig } from '@dominikcz/greg'
360
+
361
+ export default {
362
+ srcDir: 'docs',
363
+ docsBase: '',
364
+ mainTitle: 'My Docs',
365
+ } satisfies GregConfig
366
+ ```
367
+
368
+ `srcDir` can also be an array when your docs are split across multiple folders:
369
+
370
+ ```ts
371
+ import type { GregConfig } from '@dominikcz/greg'
372
+
373
+ export default {
374
+ srcDir: ['docs', 'api-docs', 'handbook'],
375
+ docsBase: '',
376
+ } satisfies GregConfig
377
+ ```
378
+
379
+ When multiple folders contain the same relative path (for example `guide/index.md`),
380
+ the later entry in the `srcDir` array overrides the earlier one.
381
+
382
+ > **Note:** `svelte.config` must remain a `.js` file — `@sveltejs/vite-plugin-svelte` loads it directly via Node ESM without a TypeScript transform.
383
+
384
+ ## Links
385
+
386
+ - [Documentation](https://github.com/dominikcz/greg)
387
+ - [GitHub](https://github.com/dominikcz/greg)
388
+ - [npm](https://www.npmjs.com/package/@dominikcz/greg)
389
+
390
+ ---
391
+
392
+ ## TODO
393
+
394
+ - [ ] AI search integration
395
+ - [ ] edit mode
396
+ - [ ] comments
397
+ - [ ] code cleanup
package/bin/greg.js ADDED
@@ -0,0 +1,241 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * greg CLI
4
+ *
5
+ * Usage:
6
+ * greg init Initialise a new documentation project
7
+ * greg dev Start the Vite development server
8
+ * greg build Build for production (auto-detects versioning config)
9
+ * greg build:static Build for production and generate static route files
10
+ * greg build:markdown Export resolved markdown files
11
+ * greg preview Preview the production build
12
+ * greg search-server Start the standalone search server (production)
13
+ * greg --version Print the Greg version
14
+ * greg --help Show this help message
15
+ */
16
+ import { spawnSync, fork } from 'node:child_process';
17
+ import { createRequire } from 'node:module';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { resolve, dirname } from 'node:path';
20
+ import { DEFAULT_OUTPUT_BASE_DIR } from '../src/lib/MarkdownDocs/versioningDefaults.js';
21
+ import { loadGregConfig } from '../src/lib/MarkdownDocs/loadGregConfig.js';
22
+
23
+ const __dirname = dirname(fileURLToPath(import.meta.url));
24
+ const require = createRequire(import.meta.url);
25
+ const pkg = require('../package.json');
26
+ const USE_COLOR = process.stdout.isTTY && !process.env.NO_COLOR;
27
+
28
+ const [, , command, ...args] = process.argv;
29
+
30
+ function color(text, code) {
31
+ return USE_COLOR ? `\x1b[${code}m${text}\x1b[0m` : text;
32
+ }
33
+
34
+ function infoTag() {
35
+ return color('[greg]', '1;36');
36
+ }
37
+
38
+ function warnTag() {
39
+ return color('[greg:warn]', '1;33');
40
+ }
41
+
42
+ function errorTag() {
43
+ return color('[greg:error]', '1;31');
44
+ }
45
+
46
+ function help() {
47
+ console.log(`
48
+ greg v${pkg.version}
49
+
50
+ Usage: greg <command> [options]
51
+
52
+ Commands:
53
+ init Initialise a new documentation project (interactive)
54
+ dev Start the Vite development server
55
+ build Build for production (auto-detects versioning config)
56
+ build:static Build and generate static route files
57
+ build:markdown Export resolved markdown files to dist/resolved-markdown
58
+ preview Preview the production build
59
+ search-server Start the standalone search API server (production)
60
+ Options: --index <path> --port <number> --host <addr>
61
+ --url <path> (endpoint path, default /api/search)
62
+ --cors-origin <value> (default *)
63
+ --cors-methods <value> (default "GET, OPTIONS")
64
+ --cors-headers <value> (default "Content-Type")
65
+ --cors-max-age <value> (default 86400)
66
+ ai-server Start the standalone AI/RAG API server (production)
67
+ Options: --index <path> (default dist/search-index.json)
68
+ --port <number> (default 3200)
69
+ --host <addr> (default localhost)
70
+ --url <path> (endpoint path, default /api/ai)
71
+ --provider <name> (ollama|openai, default ollama)
72
+ --model <name> (LLM model override)
73
+ --ollama-url <url>(default http://localhost:11434)
74
+ --cors-origin / --cors-methods / --cors-headers / --cors-max-age
75
+
76
+ Options:
77
+ --version Show version number
78
+ --help Show this help message
79
+ --single With 'build': force a single vite build
80
+ --clean-versions With 'build' + versioning: remove versioned output before build
81
+ --rebuild-all With 'build' + versioning: rebuild all versions and skip build cache
82
+ `);
83
+ }
84
+
85
+ function run(cmd, extraArgs = [], options = {}) {
86
+ const { exit = true } = options;
87
+ const result = spawnSync(cmd, extraArgs, {
88
+ stdio: 'inherit',
89
+ shell: true,
90
+ // Ensure the local node_modules/.bin is on the PATH so that
91
+ // the project-local vite binary is preferred.
92
+ env: {
93
+ ...process.env,
94
+ PATH: resolve(__dirname, '../node_modules/.bin') +
95
+ (process.platform === 'win32' ? ';' : ':') +
96
+ (process.env.PATH ?? ''),
97
+ },
98
+ });
99
+ const status = result.status ?? 0;
100
+ if (exit) process.exit(status);
101
+ return status;
102
+ }
103
+
104
+ function runNodeScript(scriptPath, extraArgs = [], options = {}) {
105
+ const { exit = true } = options;
106
+ const result = spawnSync(process.execPath, [scriptPath, ...extraArgs], {
107
+ stdio: 'inherit',
108
+ env: {
109
+ ...process.env,
110
+ PATH: resolve(__dirname, '../node_modules/.bin') +
111
+ (process.platform === 'win32' ? ';' : ':') +
112
+ (process.env.PATH ?? ''),
113
+ },
114
+ });
115
+ const status = result.status ?? 0;
116
+ if (exit) process.exit(status);
117
+ return status;
118
+ }
119
+
120
+ function printElapsedSeconds(startMs) {
121
+ const elapsed = ((Date.now() - startMs) / 1000).toFixed(1);
122
+ console.log(`\n${infoTag()} ${color(`Done in ${elapsed}s`, '32')}`);
123
+ }
124
+
125
+ async function hasVersioningBuildConfig() {
126
+ try {
127
+ const config = await loadGregConfig();
128
+ const versioning = config?.versioning;
129
+ if (!versioning || typeof versioning !== 'object' || Array.isArray(versioning)) return false;
130
+
131
+ const hasBranches = Array.isArray(versioning.branches) && versioning.branches.length > 0;
132
+ const hasFolders = Array.isArray(versioning.folders) && versioning.folders.length > 0;
133
+ const hasFoldersDir = typeof versioning.foldersDir === 'string' && versioning.foldersDir.trim().length > 0;
134
+ return hasBranches || hasFolders || hasFoldersDir;
135
+ } catch (error) {
136
+ console.warn(`${warnTag()} Could not read greg.config.* (${error?.message || error}). Falling back to single build.`);
137
+ return false;
138
+ }
139
+ }
140
+
141
+ function resolveSiteOutDir(config) {
142
+ return String(config?.outDir || DEFAULT_OUTPUT_BASE_DIR).trim() || DEFAULT_OUTPUT_BASE_DIR;
143
+ }
144
+
145
+ function resolveDocsSourceDir(config) {
146
+ return String(config?.srcDir || 'docs').trim() || 'docs';
147
+ }
148
+
149
+ function resolveDocsBase(config) {
150
+ const docsBaseValue = Object.prototype.hasOwnProperty.call(config || {}, 'docsBase')
151
+ ? config.docsBase
152
+ : '';
153
+ const cleaned = String(docsBaseValue ?? '').trim().replace(/^\/+|\/+$/g, '');
154
+ return '/' + cleaned;
155
+ }
156
+
157
+ switch (command) {
158
+ case 'init': {
159
+ const initScript = resolve(__dirname, 'init.js');
160
+ const child = fork(initScript, args, { stdio: 'inherit' });
161
+ child.on('exit', code => process.exit(code ?? 0));
162
+ break;
163
+ }
164
+ case 'dev':
165
+ run('vite', args);
166
+ break;
167
+ case 'build': {
168
+ const startedAt = Date.now();
169
+ const forceSingle = args.includes('--single');
170
+ const passthroughArgs = args.filter((a) => a !== '--single');
171
+ const shouldBuildVersions = !forceSingle && await hasVersioningBuildConfig();
172
+
173
+ if (shouldBuildVersions) {
174
+ console.log(`${infoTag()} ${color('versioning config detected. Running multi-version build.', '36')}`);
175
+ const versionsScript = resolve(__dirname, '../scripts/build-versions.js');
176
+ const status = runNodeScript(versionsScript, passthroughArgs, { exit: false });
177
+ printElapsedSeconds(startedAt);
178
+ process.exit(status);
179
+ }
180
+
181
+ const status = run('vite build', passthroughArgs, { exit: false });
182
+ printElapsedSeconds(startedAt);
183
+ process.exit(status);
184
+ }
185
+ case 'build:static': {
186
+ const startedAt = Date.now();
187
+ const config = await loadGregConfig();
188
+ const distDir = resolveSiteOutDir(config);
189
+ const docsDir = resolveDocsSourceDir(config);
190
+ const srcDir = resolveDocsBase(config);
191
+ const buildStatus = run('vite build', args, { exit: false });
192
+ if (buildStatus !== 0) {
193
+ printElapsedSeconds(startedAt);
194
+ process.exit(buildStatus);
195
+ }
196
+ const staticScript = resolve(__dirname, '../scripts/generate-static.js');
197
+ const status = runNodeScript(
198
+ staticScript,
199
+ ['--docsDir', docsDir, '--srcDir', srcDir, '--distDir', distDir],
200
+ { exit: false },
201
+ );
202
+ printElapsedSeconds(startedAt);
203
+ process.exit(status);
204
+ break;
205
+ }
206
+ case 'build:markdown': {
207
+ const markdownScript = resolve(__dirname, '../scripts/render-markdown.js');
208
+ runNodeScript(markdownScript, args);
209
+ break;
210
+ }
211
+ case 'preview':
212
+ run('vite preview', args);
213
+ break;
214
+ case 'search-server': {
215
+ // Run the standalone search server directly in this process
216
+ // (no shell needed - it is a Node.js script in the package).
217
+ const serverScript = resolve(__dirname, '../src/lib/MarkdownDocs/searchServer.js');
218
+ const child = fork(serverScript, args, { stdio: 'inherit' });
219
+ child.on('exit', code => process.exit(code ?? 0));
220
+ break;
221
+ }
222
+ case 'ai-server': {
223
+ const aiServerScript = resolve(__dirname, '../src/lib/MarkdownDocs/aiServer.js');
224
+ const child = fork(aiServerScript, args, { stdio: 'inherit' });
225
+ child.on('exit', code => process.exit(code ?? 0));
226
+ break;
227
+ }
228
+ case '--version':
229
+ case '-v':
230
+ console.log(pkg.version);
231
+ break;
232
+ case '--help':
233
+ case '-h':
234
+ case undefined:
235
+ help();
236
+ break;
237
+ default:
238
+ console.error(`${errorTag()} Unknown command: ${command}\n`);
239
+ help();
240
+ process.exit(1);
241
+ }