@gitpagedocs/cli 1.1.61 → 1.1.63

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 (72) hide show
  1. package/README.md +193 -191
  2. package/ai/application/ai-command.ts +24 -24
  3. package/ai/application/ai-provider-factory.ts +22 -22
  4. package/ai/application/docs-pattern.ts +68 -68
  5. package/ai/application/run-ai-cli-command.ts +167 -167
  6. package/ai/config.ts +50 -50
  7. package/ai/core/models/ai-cli-config.ts +33 -33
  8. package/ai/core/models/parse-ai-cli-config.ts +78 -78
  9. package/ai/core/ports/illm-provider.ts +32 -32
  10. package/ai/infrastructure/ai-config-file.ts +101 -101
  11. package/ai/infrastructure/file-system-adapter.ts +85 -85
  12. package/ai/infrastructure/llm/tools-llm-provider.ts +54 -54
  13. package/ai/infrastructure/version-docs-writer.ts +143 -143
  14. package/ai/presentation/ai-prompts.ts +239 -239
  15. package/application/config-only/handler.mjs +2 -0
  16. package/application/home/handler.mjs +2 -0
  17. package/application/ports/cli-runtime-ports.ts +91 -87
  18. package/application/report/config-only-reporter.mjs +64 -63
  19. package/application/use-cases/dispatch-mode.ts +18 -18
  20. package/builders/config-orchestrator.mjs +34 -34
  21. package/builders/project-links.mjs +50 -26
  22. package/builders/root-config-builder.d.mts +16 -0
  23. package/builders/root-config-builder.mjs +61 -53
  24. package/builders/route-builders.mjs +136 -136
  25. package/builders/theme-template.mjs +76 -76
  26. package/builders/version-config-builder.mjs +186 -186
  27. package/content/docs-en.mjs +549 -545
  28. package/content/docs-es.mjs +462 -460
  29. package/content/docs-pt.mjs +462 -460
  30. package/contracts/doc-versions.mjs +3 -3
  31. package/contracts/index.mjs +10 -0
  32. package/contracts/layouts-paths.d.mts +17 -0
  33. package/contracts/layouts-paths.mjs +68 -0
  34. package/data/default-site-config.mjs +321 -321
  35. package/data/i18n-langmenu.mjs +347 -347
  36. package/data/layouts.mjs +436 -436
  37. package/data/path-mappings.mjs +26 -26
  38. package/data/route-metas.mjs +93 -93
  39. package/data/theme-colors.mjs +443 -443
  40. package/data/urls.mjs +12 -12
  41. package/domain/models/cli-options.ts +33 -18
  42. package/domain/services/layouts-migration.d.mts +15 -0
  43. package/domain/services/layouts-migration.mjs +60 -0
  44. package/home/constants.mjs +4 -4
  45. package/index.mjs +37 -37
  46. package/infrastructure/gitpagedocs-config-file.ts +47 -47
  47. package/infrastructure/home/runtime.mjs +37 -37
  48. package/package.json +3 -3
  49. package/presentation/commands/ai-info.ts +57 -57
  50. package/presentation/commands/config-clear.ts +23 -23
  51. package/presentation/commands/config-info.ts +24 -24
  52. package/presentation/commands/diagnostics.ts +164 -164
  53. package/presentation/commands/docs.ts +37 -37
  54. package/presentation/commands/mcp.ts +20 -20
  55. package/presentation/commands/pages.ts +101 -101
  56. package/presentation/commands/password.ts +62 -62
  57. package/presentation/commands/run-command.ts +70 -70
  58. package/presentation/index.ts +124 -116
  59. package/presentation/options/parser.ts +119 -104
  60. package/presentation/options/resolver.ts +46 -48
  61. package/presentation/options/schema.ts +4 -0
  62. package/presentation/ui/clack.ts +91 -91
  63. package/presentation/ui/layouts-prompts.ts +124 -0
  64. package/presentation/ui/prompts.ts +146 -138
  65. package/presentation/ui/tty.ts +37 -0
  66. package/runtime/git-ops.mjs +110 -110
  67. package/runtime/layouts-migrator.d.mts +11 -0
  68. package/runtime/layouts-migrator.mjs +103 -0
  69. package/runtime/output.mjs +159 -146
  70. package/runtime/workflow.mjs +129 -129
  71. package/start.mjs +12 -12
  72. package/ui/logger.mjs +9 -9
@@ -1,143 +1,143 @@
1
- import fs from "node:fs/promises";
2
- import path from "node:path";
3
- // @ts-expect-error .mjs runtime module is type-less in this package.
4
- import { buildMdRoute } from "../../builders/route-builders.mjs";
5
- import type { AiDocPage } from "../application/docs-pattern";
6
-
7
- const CANONICAL_LANGS = ["pt", "en", "es"] as const;
8
- type Lang = (typeof CANONICAL_LANGS)[number];
9
-
10
- /** AI routes/menus use a high, dedicated id range so they never clash with the
11
- * deterministic base routes (ids 1..N) and can be identified for idempotency. */
12
- const AI_ROUTE_ID_BASE = 1000;
13
-
14
- export interface VersionDocsWriteInput {
15
- cwd: string;
16
- versionId: string;
17
- /** Pages generated per language (only the languages the user selected). */
18
- pagesByLang: Partial<Record<Lang, AiDocPage[]>>;
19
- }
20
-
21
- export interface VersionDocsWriteResult {
22
- configPath: string;
23
- slugs: string[];
24
- files: string[];
25
- }
26
-
27
- interface LangContent {
28
- title: string;
29
- body: string;
30
- }
31
-
32
- function indexBySlug(pages: AiDocPage[] | undefined): Map<string, AiDocPage> {
33
- const map = new Map<string, AiDocPage>();
34
- for (const page of pages ?? []) {
35
- if (!map.has(page.slug)) map.set(page.slug, page);
36
- }
37
- return map;
38
- }
39
-
40
- /**
41
- * Write AI-generated pages into the gitpagedocs versioned structure and wire
42
- * them into the version config.json (routes-md + menus-header-md). Pages are
43
- * written for ALL three canonical languages (missing languages reuse an
44
- * available translation) so every route path stays valid. Idempotent: any prior
45
- * `aiGenerated` routes/menus are replaced, never duplicated. The base config and
46
- * its deterministic routes are preserved untouched.
47
- */
48
- export async function writeVersionDocs(input: VersionDocsWriteInput): Promise<VersionDocsWriteResult> {
49
- const { cwd, versionId, pagesByLang } = input;
50
- const base = `gitpagedocs/docs/versions/${versionId}`;
51
-
52
- const perLang: Record<Lang, Map<string, AiDocPage>> = {
53
- pt: indexBySlug(pagesByLang.pt),
54
- en: indexBySlug(pagesByLang.en),
55
- es: indexBySlug(pagesByLang.es),
56
- };
57
-
58
- // Ordered unique slug list (prefer en order, then pt, then es).
59
- const order: string[] = [];
60
- const seen = new Set<string>();
61
- for (const lang of ["en", "pt", "es"] as Lang[]) {
62
- for (const page of pagesByLang[lang] ?? []) {
63
- if (!seen.has(page.slug)) {
64
- seen.add(page.slug);
65
- order.push(page.slug);
66
- }
67
- }
68
- }
69
- if (order.length === 0) {
70
- throw new Error("No AI pages to write.");
71
- }
72
-
73
- const resolve = (slug: string): Record<Lang, LangContent> => {
74
- const fallback = CANONICAL_LANGS.map((lang) => perLang[lang].get(slug)).find(Boolean);
75
- const out = {} as Record<Lang, LangContent>;
76
- for (const lang of CANONICAL_LANGS) {
77
- const page = perLang[lang].get(slug) ?? fallback!;
78
- out[lang] = { title: page.title, body: page.body };
79
- }
80
- return out;
81
- };
82
-
83
- // 1) Write the markdown files (all 3 canonical languages).
84
- const writtenFiles: string[] = [];
85
- for (const slug of order) {
86
- const content = resolve(slug);
87
- for (const lang of CANONICAL_LANGS) {
88
- const rel = `${base}/${lang}/${slug}.md`;
89
- const abs = path.resolve(cwd, rel);
90
- await fs.mkdir(path.dirname(abs), { recursive: true });
91
- await fs.writeFile(abs, `${content[lang].body}\n`, "utf-8");
92
- writtenFiles.push(rel);
93
- }
94
- }
95
-
96
- // 2) Patch the version config.json (raw JSON round-trip, preserve all keys).
97
- const configRel = `${base}/config.json`;
98
- const configAbs = path.resolve(cwd, configRel);
99
- let raw: string;
100
- try {
101
- raw = await fs.readFile(configAbs, "utf-8");
102
- } catch {
103
- throw new Error(
104
- `Version config not found at ${configRel}. Run the base scaffold (\`gitpagedocs\`) first.`,
105
- );
106
- }
107
- const config = JSON.parse(raw) as Record<string, unknown>;
108
-
109
- const routesMd = Array.isArray(config["routes-md"]) ? (config["routes-md"] as Array<Record<string, unknown>>) : [];
110
- const menusMd = Array.isArray(config["menus-header-md"]) ? (config["menus-header-md"] as Array<Record<string, unknown>>) : [];
111
- const keptRoutes = routesMd.filter((route) => route?.aiGenerated !== true);
112
- const keptMenus = menusMd.filter((menu) => menu?.aiGenerated !== true);
113
-
114
- const newRoutes: Array<Record<string, unknown>> = [];
115
- const newMenus: Array<Record<string, unknown>> = [];
116
- order.forEach((slug, index) => {
117
- const content = resolve(slug);
118
- const id = AI_ROUTE_ID_BASE + index + 1;
119
- const pathByLang = {
120
- pt: `${base}/pt/${slug}.md`,
121
- en: `${base}/en/${slug}.md`,
122
- es: `${base}/es/${slug}.md`,
123
- };
124
- const titles = { pt: content.pt.title, en: content.en.title, es: content.es.title };
125
- const descriptions = { pt: "", en: "", es: "" };
126
- const route = buildMdRoute(versionId, id, pathByLang, titles, descriptions, {}) as Record<string, unknown>;
127
- route.aiGenerated = true;
128
- newRoutes.push(route);
129
- newMenus.push({
130
- id,
131
- aiGenerated: true,
132
- pt: { title: content.pt.title, "path-click": pathByLang.pt },
133
- en: { title: content.en.title, "path-click": pathByLang.en },
134
- es: { title: content.es.title, "path-click": pathByLang.es },
135
- });
136
- });
137
-
138
- config["routes-md"] = [...keptRoutes, ...newRoutes];
139
- config["menus-header-md"] = [...keptMenus, ...newMenus];
140
- await fs.writeFile(configAbs, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
141
-
142
- return { configPath: configRel, slugs: order, files: writtenFiles };
143
- }
1
+ import fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ // @ts-expect-error .mjs runtime module is type-less in this package.
4
+ import { buildMdRoute } from "../../builders/route-builders.mjs";
5
+ import type { AiDocPage } from "../application/docs-pattern";
6
+
7
+ const CANONICAL_LANGS = ["pt", "en", "es"] as const;
8
+ type Lang = (typeof CANONICAL_LANGS)[number];
9
+
10
+ /** AI routes/menus use a high, dedicated id range so they never clash with the
11
+ * deterministic base routes (ids 1..N) and can be identified for idempotency. */
12
+ const AI_ROUTE_ID_BASE = 1000;
13
+
14
+ export interface VersionDocsWriteInput {
15
+ cwd: string;
16
+ versionId: string;
17
+ /** Pages generated per language (only the languages the user selected). */
18
+ pagesByLang: Partial<Record<Lang, AiDocPage[]>>;
19
+ }
20
+
21
+ export interface VersionDocsWriteResult {
22
+ configPath: string;
23
+ slugs: string[];
24
+ files: string[];
25
+ }
26
+
27
+ interface LangContent {
28
+ title: string;
29
+ body: string;
30
+ }
31
+
32
+ function indexBySlug(pages: AiDocPage[] | undefined): Map<string, AiDocPage> {
33
+ const map = new Map<string, AiDocPage>();
34
+ for (const page of pages ?? []) {
35
+ if (!map.has(page.slug)) map.set(page.slug, page);
36
+ }
37
+ return map;
38
+ }
39
+
40
+ /**
41
+ * Write AI-generated pages into the gitpagedocs versioned structure and wire
42
+ * them into the version config.json (routes-md + menus-header-md). Pages are
43
+ * written for ALL three canonical languages (missing languages reuse an
44
+ * available translation) so every route path stays valid. Idempotent: any prior
45
+ * `aiGenerated` routes/menus are replaced, never duplicated. The base config and
46
+ * its deterministic routes are preserved untouched.
47
+ */
48
+ export async function writeVersionDocs(input: VersionDocsWriteInput): Promise<VersionDocsWriteResult> {
49
+ const { cwd, versionId, pagesByLang } = input;
50
+ const base = `gitpagedocs/docs/versions/${versionId}`;
51
+
52
+ const perLang: Record<Lang, Map<string, AiDocPage>> = {
53
+ pt: indexBySlug(pagesByLang.pt),
54
+ en: indexBySlug(pagesByLang.en),
55
+ es: indexBySlug(pagesByLang.es),
56
+ };
57
+
58
+ // Ordered unique slug list (prefer en order, then pt, then es).
59
+ const order: string[] = [];
60
+ const seen = new Set<string>();
61
+ for (const lang of ["en", "pt", "es"] as Lang[]) {
62
+ for (const page of pagesByLang[lang] ?? []) {
63
+ if (!seen.has(page.slug)) {
64
+ seen.add(page.slug);
65
+ order.push(page.slug);
66
+ }
67
+ }
68
+ }
69
+ if (order.length === 0) {
70
+ throw new Error("No AI pages to write.");
71
+ }
72
+
73
+ const resolve = (slug: string): Record<Lang, LangContent> => {
74
+ const fallback = CANONICAL_LANGS.map((lang) => perLang[lang].get(slug)).find(Boolean);
75
+ const out = {} as Record<Lang, LangContent>;
76
+ for (const lang of CANONICAL_LANGS) {
77
+ const page = perLang[lang].get(slug) ?? fallback!;
78
+ out[lang] = { title: page.title, body: page.body };
79
+ }
80
+ return out;
81
+ };
82
+
83
+ // 1) Write the markdown files (all 3 canonical languages).
84
+ const writtenFiles: string[] = [];
85
+ for (const slug of order) {
86
+ const content = resolve(slug);
87
+ for (const lang of CANONICAL_LANGS) {
88
+ const rel = `${base}/${lang}/${slug}.md`;
89
+ const abs = path.resolve(cwd, rel);
90
+ await fs.mkdir(path.dirname(abs), { recursive: true });
91
+ await fs.writeFile(abs, `${content[lang].body}\n`, "utf-8");
92
+ writtenFiles.push(rel);
93
+ }
94
+ }
95
+
96
+ // 2) Patch the version config.json (raw JSON round-trip, preserve all keys).
97
+ const configRel = `${base}/config.json`;
98
+ const configAbs = path.resolve(cwd, configRel);
99
+ let raw: string;
100
+ try {
101
+ raw = await fs.readFile(configAbs, "utf-8");
102
+ } catch {
103
+ throw new Error(
104
+ `Version config not found at ${configRel}. Run the base scaffold (\`gitpagedocs\`) first.`,
105
+ );
106
+ }
107
+ const config = JSON.parse(raw) as Record<string, unknown>;
108
+
109
+ const routesMd = Array.isArray(config["routes-md"]) ? (config["routes-md"] as Array<Record<string, unknown>>) : [];
110
+ const menusMd = Array.isArray(config["menus-header-md"]) ? (config["menus-header-md"] as Array<Record<string, unknown>>) : [];
111
+ const keptRoutes = routesMd.filter((route) => route?.aiGenerated !== true);
112
+ const keptMenus = menusMd.filter((menu) => menu?.aiGenerated !== true);
113
+
114
+ const newRoutes: Array<Record<string, unknown>> = [];
115
+ const newMenus: Array<Record<string, unknown>> = [];
116
+ order.forEach((slug, index) => {
117
+ const content = resolve(slug);
118
+ const id = AI_ROUTE_ID_BASE + index + 1;
119
+ const pathByLang = {
120
+ pt: `${base}/pt/${slug}.md`,
121
+ en: `${base}/en/${slug}.md`,
122
+ es: `${base}/es/${slug}.md`,
123
+ };
124
+ const titles = { pt: content.pt.title, en: content.en.title, es: content.es.title };
125
+ const descriptions = { pt: "", en: "", es: "" };
126
+ const route = buildMdRoute(versionId, id, pathByLang, titles, descriptions, {}) as Record<string, unknown>;
127
+ route.aiGenerated = true;
128
+ newRoutes.push(route);
129
+ newMenus.push({
130
+ id,
131
+ aiGenerated: true,
132
+ pt: { title: content.pt.title, "path-click": pathByLang.pt },
133
+ en: { title: content.en.title, "path-click": pathByLang.en },
134
+ es: { title: content.es.title, "path-click": pathByLang.es },
135
+ });
136
+ });
137
+
138
+ config["routes-md"] = [...keptRoutes, ...newRoutes];
139
+ config["menus-header-md"] = [...keptMenus, ...newMenus];
140
+ await fs.writeFile(configAbs, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
141
+
142
+ return { configPath: configRel, slugs: order, files: writtenFiles };
143
+ }