@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.
- package/README.md +193 -191
- package/ai/application/ai-command.ts +24 -24
- package/ai/application/ai-provider-factory.ts +22 -22
- package/ai/application/docs-pattern.ts +68 -68
- package/ai/application/run-ai-cli-command.ts +167 -167
- package/ai/config.ts +50 -50
- package/ai/core/models/ai-cli-config.ts +33 -33
- package/ai/core/models/parse-ai-cli-config.ts +78 -78
- package/ai/core/ports/illm-provider.ts +32 -32
- package/ai/infrastructure/ai-config-file.ts +101 -101
- package/ai/infrastructure/file-system-adapter.ts +85 -85
- package/ai/infrastructure/llm/tools-llm-provider.ts +54 -54
- package/ai/infrastructure/version-docs-writer.ts +143 -143
- package/ai/presentation/ai-prompts.ts +239 -239
- package/application/config-only/handler.mjs +2 -0
- package/application/home/handler.mjs +2 -0
- package/application/ports/cli-runtime-ports.ts +91 -87
- package/application/report/config-only-reporter.mjs +64 -63
- package/application/use-cases/dispatch-mode.ts +18 -18
- package/builders/config-orchestrator.mjs +34 -34
- package/builders/project-links.mjs +50 -26
- package/builders/root-config-builder.d.mts +16 -0
- package/builders/root-config-builder.mjs +61 -53
- package/builders/route-builders.mjs +136 -136
- package/builders/theme-template.mjs +76 -76
- package/builders/version-config-builder.mjs +186 -186
- package/content/docs-en.mjs +549 -545
- package/content/docs-es.mjs +462 -460
- package/content/docs-pt.mjs +462 -460
- package/contracts/doc-versions.mjs +3 -3
- package/contracts/index.mjs +10 -0
- package/contracts/layouts-paths.d.mts +17 -0
- package/contracts/layouts-paths.mjs +68 -0
- package/data/default-site-config.mjs +321 -321
- package/data/i18n-langmenu.mjs +347 -347
- package/data/layouts.mjs +436 -436
- package/data/path-mappings.mjs +26 -26
- package/data/route-metas.mjs +93 -93
- package/data/theme-colors.mjs +443 -443
- package/data/urls.mjs +12 -12
- package/domain/models/cli-options.ts +33 -18
- package/domain/services/layouts-migration.d.mts +15 -0
- package/domain/services/layouts-migration.mjs +60 -0
- package/home/constants.mjs +4 -4
- package/index.mjs +37 -37
- package/infrastructure/gitpagedocs-config-file.ts +47 -47
- package/infrastructure/home/runtime.mjs +37 -37
- package/package.json +3 -3
- package/presentation/commands/ai-info.ts +57 -57
- package/presentation/commands/config-clear.ts +23 -23
- package/presentation/commands/config-info.ts +24 -24
- package/presentation/commands/diagnostics.ts +164 -164
- package/presentation/commands/docs.ts +37 -37
- package/presentation/commands/mcp.ts +20 -20
- package/presentation/commands/pages.ts +101 -101
- package/presentation/commands/password.ts +62 -62
- package/presentation/commands/run-command.ts +70 -70
- package/presentation/index.ts +124 -116
- package/presentation/options/parser.ts +119 -104
- package/presentation/options/resolver.ts +46 -48
- package/presentation/options/schema.ts +4 -0
- package/presentation/ui/clack.ts +91 -91
- package/presentation/ui/layouts-prompts.ts +124 -0
- package/presentation/ui/prompts.ts +146 -138
- package/presentation/ui/tty.ts +37 -0
- package/runtime/git-ops.mjs +110 -110
- package/runtime/layouts-migrator.d.mts +11 -0
- package/runtime/layouts-migrator.mjs +103 -0
- package/runtime/output.mjs +159 -146
- package/runtime/workflow.mjs +129 -129
- package/start.mjs +12 -12
- 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
|
+
}
|