@ahmedrowaihi/8n 6.0.55 → 6.0.56

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.
package/dist/index.mjs CHANGED
@@ -3738,7 +3738,7 @@ async function checkSelfUpdate() {
3738
3738
  });
3739
3739
  if (!res.ok) return;
3740
3740
  const { version: latest } = await res.json();
3741
- const current = "6.0.55";
3741
+ const current = "6.0.56";
3742
3742
  if (latest !== current) console.log(pc.yellow("⚠") + pc.dim(` new version available: `) + pc.cyan(latest) + pc.dim(` (current: ${current}) — run `) + pc.cyan("npm i -g @ahmedrowaihi/8n") + pc.dim(" to update"));
3743
3743
  } catch {}
3744
3744
  }
@@ -3851,7 +3851,7 @@ async function dev() {
3851
3851
  async function build({ server = false } = {}) {
3852
3852
  const { config, contentDir } = await resolveProject();
3853
3853
  const projectDir = process.cwd();
3854
- console.log(pc.cyan("8n") + pc.dim(` v6.0.55 build → ${contentDir}`));
3854
+ console.log(pc.cyan("8n") + pc.dim(` v6.0.56 build → ${contentDir}`));
3855
3855
  if (server) await runNextFlat(projectDir, "build", buildEnv({
3856
3856
  config,
3857
3857
  contentDir,
@@ -3924,22 +3924,14 @@ const SCAFFOLD = {
3924
3924
  // nav: { links: [{ text: "Blog", url: "https://example.com/blog" }] },
3925
3925
  };
3926
3926
  `,
3927
- ["content/docs/en/meta.json"]: JSON.stringify({
3928
- title: "Documentation",
3929
- pages: ["index", "getting-started"]
3930
- }, null, 2) + "\n",
3931
- ["content/docs/en/index.mdx"]: `---
3927
+ ["content/docs/index.mdx"]: `---
3932
3928
  title: Introduction
3933
3929
  description: Welcome to the docs.
3934
3930
  ---
3935
3931
 
3936
3932
  Welcome to your documentation. Edit files in \`content/\` and run \`8n dev\` to start.
3937
3933
  `,
3938
- ["content/docs/en/getting-started/meta.json"]: JSON.stringify({
3939
- title: "Getting Started",
3940
- pages: ["installation"]
3941
- }, null, 2) + "\n",
3942
- ["content/docs/en/getting-started/installation.mdx"]: `---
3934
+ ["content/docs/getting-started/installation.mdx"]: `---
3943
3935
  title: Installation
3944
3936
  description: How to install and set up the project.
3945
3937
  ---
@@ -3948,7 +3940,7 @@ description: How to install and set up the project.
3948
3940
 
3949
3941
  Add your installation steps here.
3950
3942
  `,
3951
- ["content/home/en/index.mdx"]: `---
3943
+ ["content/home/index.mdx"]: `---
3952
3944
  title: Home
3953
3945
  ---
3954
3946
 
@@ -3957,21 +3949,77 @@ title: Home
3957
3949
  Welcome to your docs.
3958
3950
  </h1>
3959
3951
  <div className="text-muted-foreground text-lg max-w-md leading-relaxed">
3960
- Edit \`content/home/en/index.mdx\` to customize this page.
3952
+ Edit \`content/home/index.mdx\` to customize this page.
3961
3953
  </div>
3962
3954
  </div>
3963
3955
  `,
3964
- ["content/changelog/en/meta.json"]: JSON.stringify({ title: "Changelog" }, null, 2) + "\n",
3965
- ["content/changelog/en/v1.0.0.mdx"]: `---
3956
+ ["content/changelog/v1.0.0.mdx"]: `---
3966
3957
  title: Version 1.0.0
3967
- version: 1.0.0
3968
- date: "${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}"
3969
- summary: Initial release.
3970
3958
  ---
3971
3959
 
3972
3960
  ## Initial Release
3973
3961
 
3974
3962
  First version of the docs.
3963
+ `,
3964
+ ["CLAUDE.md"]: `# 8n Docs Project
3965
+
3966
+ This project uses the [8n](https://github.com/ahmedrowaihi/8n) docs framework — a Next.js-based documentation site builder.
3967
+
3968
+ ## Content structure
3969
+
3970
+ All documentation lives in \`content/\`. Each top-level subdirectory is a **section** (e.g. \`docs\`, \`api\`, \`changelog\`). Sections are auto-discovered and appear in the sidebar.
3971
+
3972
+ \`\`\`
3973
+ content/
3974
+ home/
3975
+ index.mdx ← landing page (not in sidebar)
3976
+ docs/
3977
+ index.mdx ← section landing page (frontmatter only = sidebar group title)
3978
+ getting-started/
3979
+ installation.mdx
3980
+ changelog/
3981
+ v1.0.0.mdx
3982
+ \`\`\`
3983
+
3984
+ ## Adding a page
3985
+
3986
+ Drop an \`.mdx\` file anywhere under the relevant section. Files are sorted by numeric prefix (\`01-\`, \`02-\`…); the prefix is stripped from the URL slug.
3987
+
3988
+ ## Translations (i18n)
3989
+
3990
+ Add a sibling file with the locale suffix to translate a page:
3991
+
3992
+ \`\`\`
3993
+ docs/
3994
+ getting-started.mdx ← English (default)
3995
+ getting-started.ar.mdx ← Arabic translation
3996
+ \`\`\`
3997
+
3998
+ No folder restructuring needed. Files without a locale suffix belong to the default locale.
3999
+
4000
+ ## Frontmatter fields
4001
+
4002
+ | Field | Used in | Notes |
4003
+ |---------------|-----------------|----------------------------------------|
4004
+ | \`title\` | all pages | required |
4005
+ | \`description\` | docs/api | shown in meta and cards |
4006
+ | \`label\` | any index.mdx | overrides sidebar group display name |
4007
+ | \`icon\` | any index.mdx | sidebar group icon |
4008
+ | \`redirect\` | any | immediately redirects to another URL |
4009
+
4010
+ ## CLI commands
4011
+
4012
+ \`\`\`bash
4013
+ 8n dev # start dev server
4014
+ 8n build # production build (static export)
4015
+ 8n build --server # production build (SSR and Server Routes)
4016
+ 8n generate:api -i openapi.json -o api # generate API docs from OpenAPI spec
4017
+ 8n mcp # start MCP server for AI-assisted authoring
4018
+ \`\`\`
4019
+
4020
+ ## MCP server
4021
+
4022
+ Run \`8n mcp\` and point your AI assistant at it for context-aware docs authoring. The MCP server exposes the full component reference and project conventions as tools.
3975
4023
  `
3976
4024
  };
3977
4025
  const GITIGNORE_ENTRIES = [
@@ -4156,20 +4204,26 @@ function deploy(target) {
4156
4204
 
4157
4205
  //#endregion
4158
4206
  //#region src/commands/mcp.ts
4159
- async function listMdFiles(dir) {
4207
+ function isLocaleSuffixed(filename) {
4208
+ return /\.[a-z]{2,5}\.(mdx|md)$/.test(filename);
4209
+ }
4210
+ function stripNumericPrefix(name) {
4211
+ return name.replace(/^\d+-/, "");
4212
+ }
4213
+ async function listKnowledgeFiles(dir) {
4160
4214
  let entries;
4161
4215
  try {
4162
4216
  entries = await readdir(dir, { withFileTypes: true });
4163
4217
  } catch {
4164
4218
  return [];
4165
4219
  }
4166
- return entries.filter((e) => !e.isDirectory() && (e.name.endsWith(".mdx") || e.name.endsWith(".md"))).map((e) => e.name);
4220
+ return entries.filter((e) => !e.isDirectory() && (e.name.endsWith(".mdx") || e.name.endsWith(".md")) && !isLocaleSuffixed(e.name)).map((e) => e.name);
4167
4221
  }
4168
4222
  async function mcp() {
4169
- const mcpDir = join(getStarterDir(), "content", "mcp", "en");
4223
+ const mcpDir = join(getStarterDir(), "content", "mcp");
4170
4224
  const server = new McpServer({
4171
4225
  name: "8n",
4172
- version: "6.0.55"
4226
+ version: "6.0.56"
4173
4227
  });
4174
4228
  server.registerTool("read_me", {
4175
4229
  description: "Returns how to use the 8n MCP tools. Call this BEFORE documenting anything with 8n.",
@@ -4206,7 +4260,7 @@ Example: get_component({ name: "components" }) returns all available MDX compone
4206
4260
  }] };
4207
4261
  return { content: [{
4208
4262
  type: "text",
4209
- text: (await listMdFiles(mcpDir)).map((f) => basename(f, extname(f))).join("\n")
4263
+ text: (await listKnowledgeFiles(mcpDir)).map((f) => stripNumericPrefix(basename(f, extname(f)))).filter((n) => n !== "index").join("\n")
4210
4264
  }] };
4211
4265
  });
4212
4266
  server.registerTool("get_component", {
@@ -4217,28 +4271,23 @@ Example: get_component({ name: "components" }) returns all available MDX compone
4217
4271
  type: "text",
4218
4272
  text: "8n MCP knowledge not found. Reinstall @ahmedrowaihi/8n."
4219
4273
  }] };
4220
- for (const ext of [".mdx", ".md"]) {
4221
- const file = join(mcpDir, `${name}${ext}`);
4222
- if (existsSync(file)) return { content: [{
4223
- type: "text",
4224
- text: await readFile(file, "utf-8")
4225
- }] };
4226
- }
4274
+ const match = (await listKnowledgeFiles(mcpDir)).find((f) => stripNumericPrefix(basename(f, extname(f))) === name);
4275
+ if (match) return { content: [{
4276
+ type: "text",
4277
+ text: await readFile(join(mcpDir, match), "utf-8")
4278
+ }] };
4227
4279
  return { content: [{
4228
4280
  type: "text",
4229
4281
  text: `Unknown topic: ${name}. Call list_components to see available topics.`
4230
4282
  }] };
4231
4283
  });
4232
4284
  server.registerTool("analyze", {
4233
- description: "Runs static analysis on the user's content directory and reports issues that may break the documentation site.",
4285
+ description: "Checks frontmatter in the user's content directory and reports missing required fields.",
4234
4286
  inputSchema: {}
4235
4287
  }, async () => {
4236
4288
  let contentDir = join(process.cwd(), "content");
4237
- let locales = ["en"];
4238
4289
  try {
4239
- const project = await resolveProject();
4240
- contentDir = project.contentDir;
4241
- locales = project.config.locales ?? ["en"];
4290
+ contentDir = (await resolveProject()).contentDir;
4242
4291
  } catch {}
4243
4292
  const issues = [];
4244
4293
  async function walkAll(dir) {
@@ -4256,44 +4305,11 @@ Example: get_component({ name: "components" }) returns all available MDX compone
4256
4305
  }
4257
4306
  return results;
4258
4307
  }
4259
- const allFiles = await walkAll(contentDir);
4260
- const mdxFiles = allFiles.filter((f) => f.endsWith(".mdx") || f.endsWith(".md"));
4261
- const metaFiles = allFiles.filter((f) => f.endsWith("meta.json"));
4308
+ const mdxFiles = (await walkAll(contentDir)).filter((f) => f.endsWith(".mdx") || f.endsWith(".md"));
4262
4309
  for (const file of mdxFiles) {
4263
4310
  const raw = await readFile(file, "utf-8").catch(() => "");
4264
4311
  const rel = relative(contentDir, file);
4265
4312
  if (!raw.match(/^---[\s\S]*?\ntitle:/m)) issues.push(`Missing title in frontmatter: ${rel}`);
4266
- if (rel.startsWith("changelog/")) {
4267
- if (!raw.match(/\nversion:/)) issues.push(`Changelog page missing version: ${rel}`);
4268
- if (!raw.match(/\ndate:/)) issues.push(`Changelog page missing date: ${rel}`);
4269
- }
4270
- const bodyMatch = raw.match(/^---[\s\S]*?---\s*([\s\S]*)$/m);
4271
- if (bodyMatch && bodyMatch[1].trim() === "") issues.push(`Empty page body: ${rel}`);
4272
- }
4273
- for (const file of metaFiles) {
4274
- const rel = relative(contentDir, file);
4275
- const raw = await readFile(file, "utf-8").catch(() => "");
4276
- let meta;
4277
- try {
4278
- meta = JSON.parse(raw);
4279
- } catch {
4280
- issues.push(`Malformed JSON: ${rel}`);
4281
- continue;
4282
- }
4283
- if (meta.pages) {
4284
- const dir = join(file, "..");
4285
- for (const page of meta.pages) {
4286
- if (page.startsWith("...") || page === "---" || page.startsWith("[")) continue;
4287
- if (existsSync(join(dir, page)) && !existsSync(join(dir, `${page}.mdx`)) && !existsSync(join(dir, `${page}.md`))) continue;
4288
- if (![".mdx", ".md"].some((ext) => existsSync(join(dir, `${page}${ext}`)))) issues.push(`meta.json references missing page "${page}": ${rel}`);
4289
- }
4290
- }
4291
- }
4292
- const defaultLocale = locales[0];
4293
- const otherLocales = locales.slice(1);
4294
- for (const locale of otherLocales) {
4295
- const defaultFiles = mdxFiles.filter((f) => f.includes(`/${defaultLocale}/`)).map((f) => relative(contentDir, f).replace(`${defaultLocale}/`, `${locale}/`));
4296
- for (const expected of defaultFiles) if (!existsSync(join(contentDir, expected))) issues.push(`Missing ${locale} translation: ${expected}`);
4297
4313
  }
4298
4314
  if (issues.length === 0) return { content: [{
4299
4315
  type: "text",
@@ -4325,7 +4341,7 @@ async function generateApi({ input, output }) {
4325
4341
 
4326
4342
  //#endregion
4327
4343
  //#region src/index.ts
4328
- const program = new Command().name("8n").description("Run your 8n docs site").version("6.0.55").addOption(new Option("--debug").hideHelp()).hook("preAction", (cmd) => {
4344
+ const program = new Command().name("8n").description("Run your 8n docs site").version("6.0.56").addOption(new Option("--debug").hideHelp()).hook("preAction", (cmd) => {
4329
4345
  if (cmd.opts().debug) process.env.DEBUG_8N = "1";
4330
4346
  });
4331
4347
  program.command("init").description("Scaffold a new docs project in the current directory").action(init);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahmedrowaihi/8n",
3
- "version": "6.0.55",
3
+ "version": "6.0.56",
4
4
  "description": "8n docs — run your docs site from your content directory",
5
5
  "bin": {
6
6
  "8n": "./dist/index.mjs"
@@ -1,8 +1,5 @@
1
1
  ---
2
2
  title: الإصدار 1.0.0
3
- version: 1.0.0
4
- date: "2026-03-14"
5
- summary: الإصدار الأول — توثيق ثنائي اللغة بدعم RTL كامل، بحث محلي، خطوط ثمانية، مكوّنات MDX غنية، Excalidraw، تضمين التغريدات، رياضيات، TwoSlash، تغذيات RSS، وملف LLMs.txt.
6
3
  ---
7
4
 
8
5
  ## الإصدار الأول
@@ -50,4 +47,4 @@ summary: الإصدار الأول — توثيق ثنائي اللغة بدعم
50
47
  | تغذيات RSS | تُولَّد تلقائيًا على `/{lang}/rss.xml` للغتين |
51
48
  | ملف LLMs.txt | `/llms.txt` و`/llms-full.txt` وفق اتفاقية [llms.txt](https://llmstxt.org) |
52
49
  | تواريخ آخر تعديل | تاريخ آخر تعديل git لكل صفحة عبر `fumadocs-mdx/plugins/last-modified` |
53
- | سجل التغييرات | مصدر `content/changelog/` ثنائي اللغة بحقول `version` و`date` و`summary` |
50
+ | سجل التغييرات | قسم `content/changelog/` ثنائي اللغة |
@@ -1,8 +1,5 @@
1
1
  ---
2
2
  title: Version 1.0.0
3
- version: 1.0.0
4
- date: "2026-03-14"
5
- summary: Initial release — bilingual docs with full RTL support, offline search, Thmanyah fonts, rich MDX components, Excalidraw, Tweet embeds, math, TwoSlash, RSS feeds, and LLMs.txt.
6
3
  ---
7
4
 
8
5
  ## Initial Release
@@ -50,4 +47,4 @@ Full-text search powered by [Orama](https://orama.com) runs entirely in the brow
50
47
  | RSS feeds | Auto-generated at `/{lang}/rss.xml` for both locales |
51
48
  | LLMs.txt | `/llms.txt` and `/llms-full.txt` following the [llms.txt](https://llmstxt.org) convention |
52
49
  | Last modified dates | Per-page git last-modified date via `fumadocs-mdx/plugins/last-modified` |
53
- | Changelog | Bilingual `content/changelog/` source with `version`, `date`, and `summary` fields |
50
+ | Changelog | Bilingual `content/changelog/` section |
@@ -22,7 +22,7 @@ content/
22
22
  ui/ ← UI component showcase (optional)
23
23
  index.mdx
24
24
  badge.mdx
25
- changelog/ ← versioned changelog, sorted newest-first
25
+ changelog/ ← changelog section
26
26
  index.mdx
27
27
  v2.0.0.mdx
28
28
  v1.0.0.mdx
@@ -31,17 +31,6 @@ Optional body — makes this file a real landing page.
31
31
  Omit the body to treat it as metadata-only; the section root will redirect to the first child page.
32
32
  ```
33
33
 
34
- ## Changelog pages
35
-
36
- ```mdx
37
- ---
38
- title: Version 2.1.0
39
- version: 2.1.0 # semver string — used for sorting
40
- date: "2025-06-01" # ISO 8601 date (quoted to prevent YAML date parsing)
41
- summary: What changed. # one-liner shown in the changelog list view
42
- ---
43
- ```
44
-
45
34
  ## Home page (`home/index.mdx`)
46
35
 
47
36
  Free-form MDX — no required fields. All components and Tailwind utility classes are available.
@@ -49,7 +38,7 @@ Use `title` and `description` frontmatter if you want them in `<meta>` tags.
49
38
 
50
39
  ## Notes
51
40
 
52
- - `title` is the only truly required field on docs/api/ui pages.
41
+ - `title` is the only truly required field on any page.
53
42
  - `label` lets you have a short sidebar name while keeping a longer `title` in the page heading.
54
43
  - All string values should be unquoted unless they contain special YAML characters (`:`, `#`, etc.).
55
44
  - `icon` accepts any name from the [Lucide icon set](https://lucide.dev/icons/).
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ahmedrowaihi/8n-starter",
3
- "version": "6.0.55",
3
+ "version": "6.0.56",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "exports": {