@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,62 +1,62 @@
1
- import { NodeCryptoService, deriveDocAccessKeys } from "@gitpagedocs/tools";
2
- import type { CommandContext } from "./run-command";
3
- import { askPassword, note, outro } from "../ui/clack";
4
- import { interactivePromptsAvailable } from "../ui/prompts";
5
- import { GitPageDocsConfigRepository } from "../../infrastructure/gitpagedocs-config-file";
6
-
7
- const MIN_PASSWORD_LENGTH = 4;
8
-
9
- /**
10
- * `gitpagedocs password` — interactively set a documentation access password.
11
- *
12
- * Type + confirm a password, derive the double-hash key pair, write the PUBLIC
13
- * key into gitpagedocs/config.json (which makes the frontend gate the docs), and
14
- * print the PRIVATE key for the user to copy. The password itself is never stored.
15
- */
16
- export async function runPassword(ctx: CommandContext): Promise<void> {
17
- if (!interactivePromptsAvailable()) {
18
- // eslint-disable-next-line no-console
19
- console.log("\n `gitpagedocs password` is interactive — run it in a terminal (TTY).\n");
20
- return;
21
- }
22
-
23
- const password = await askPassword({
24
- message: "Documentation password:",
25
- validate: (v) =>
26
- v && v.trim().length >= MIN_PASSWORD_LENGTH
27
- ? undefined
28
- : `Use at least ${MIN_PASSWORD_LENGTH} characters.`,
29
- });
30
- const confirmation = await askPassword({
31
- message: "Confirm password:",
32
- validate: (v) => (v ? undefined : "Required."),
33
- });
34
-
35
- if (password !== confirmation) {
36
- note("Passwords do not match. Nothing was changed.", "Aborted");
37
- return;
38
- }
39
-
40
- const { privateKey, publicKey } = await deriveDocAccessKeys(password, new NodeCryptoService());
41
-
42
- let configPath: string;
43
- try {
44
- configPath = await new GitPageDocsConfigRepository(ctx.cwd).patchDocsAccess(publicKey);
45
- } catch (error) {
46
- note(error instanceof Error ? error.message : String(error), "Could not save");
47
- return;
48
- }
49
-
50
- note(
51
- `Public key saved to ${configPath}\nThe documentation is now password-protected.`,
52
- "Saved",
53
- );
54
- // eslint-disable-next-line no-console
55
- console.log(
56
- "\n PRIVATE KEY (copy & keep it safe — it also unlocks the docs):\n\n" +
57
- ` ${privateKey}\n\n` +
58
- " Readers can unlock with the password OR this private key.\n" +
59
- " To remove protection, set site.docsAccess.enabled to false in config.json.\n",
60
- );
61
- outro("Done.");
62
- }
1
+ import { NodeCryptoService, deriveDocAccessKeys } from "@gitpagedocs/tools";
2
+ import type { CommandContext } from "./run-command";
3
+ import { askPassword, note, outro } from "../ui/clack";
4
+ import { interactivePromptsAvailable } from "../ui/prompts";
5
+ import { GitPageDocsConfigRepository } from "../../infrastructure/gitpagedocs-config-file";
6
+
7
+ const MIN_PASSWORD_LENGTH = 4;
8
+
9
+ /**
10
+ * `gitpagedocs password` — interactively set a documentation access password.
11
+ *
12
+ * Type + confirm a password, derive the double-hash key pair, write the PUBLIC
13
+ * key into gitpagedocs/config.json (which makes the frontend gate the docs), and
14
+ * print the PRIVATE key for the user to copy. The password itself is never stored.
15
+ */
16
+ export async function runPassword(ctx: CommandContext): Promise<void> {
17
+ if (!interactivePromptsAvailable()) {
18
+ // eslint-disable-next-line no-console
19
+ console.log("\n `gitpagedocs password` is interactive — run it in a terminal (TTY).\n");
20
+ return;
21
+ }
22
+
23
+ const password = await askPassword({
24
+ message: "Documentation password:",
25
+ validate: (v) =>
26
+ v && v.trim().length >= MIN_PASSWORD_LENGTH
27
+ ? undefined
28
+ : `Use at least ${MIN_PASSWORD_LENGTH} characters.`,
29
+ });
30
+ const confirmation = await askPassword({
31
+ message: "Confirm password:",
32
+ validate: (v) => (v ? undefined : "Required."),
33
+ });
34
+
35
+ if (password !== confirmation) {
36
+ note("Passwords do not match. Nothing was changed.", "Aborted");
37
+ return;
38
+ }
39
+
40
+ const { privateKey, publicKey } = await deriveDocAccessKeys(password, new NodeCryptoService());
41
+
42
+ let configPath: string;
43
+ try {
44
+ configPath = await new GitPageDocsConfigRepository(ctx.cwd).patchDocsAccess(publicKey);
45
+ } catch (error) {
46
+ note(error instanceof Error ? error.message : String(error), "Could not save");
47
+ return;
48
+ }
49
+
50
+ note(
51
+ `Public key saved to ${configPath}\nThe documentation is now password-protected.`,
52
+ "Saved",
53
+ );
54
+ // eslint-disable-next-line no-console
55
+ console.log(
56
+ "\n PRIVATE KEY (copy & keep it safe — it also unlocks the docs):\n\n" +
57
+ ` ${privateKey}\n\n` +
58
+ " Readers can unlock with the password OR this private key.\n" +
59
+ " To remove protection, set site.docsAccess.enabled to false in config.json.\n",
60
+ );
61
+ outro("Done.");
62
+ }
@@ -1,70 +1,70 @@
1
- /**
2
- * New-verb command layer (Phase 6). Intercepts the informational/utility
3
- * commands that are NOT part of the legacy flag flow (version, doctor, provider,
4
- * models, config, mcp, update) and routes them to thin handlers that consume
5
- * @gitpagedocs/tools. Alias verbs (init, document, deploy, pages) are mapped in
6
- * the parser and fall through to the legacy dispatch, so this returns false for
7
- * them.
8
- */
9
- export interface CommandContext {
10
- argv: string[];
11
- args: string[];
12
- pkgRoot: string;
13
- cwd: string;
14
- }
15
-
16
- export type CommandHandler = (ctx: CommandContext) => Promise<void>;
17
-
18
- import { runVersion, runDoctor, runUpdate } from "./diagnostics";
19
- import { runProvider, runModels } from "./ai-info";
20
- import { runConfig } from "./config-info";
21
- import { runConfigClear } from "./config-clear";
22
- import { runMcp } from "./mcp";
23
- import { runDocs } from "./docs";
24
- import { runPagesActions, runPagesDeploy } from "./pages";
25
- import { runPassword } from "./password";
26
-
27
- const REGISTRY: Record<string, CommandHandler> = {
28
- version: runVersion,
29
- "--version": runVersion,
30
- "-v": runVersion,
31
- doctor: runDoctor,
32
- update: runUpdate,
33
- provider: runProvider,
34
- providers: runProvider,
35
- models: runModels,
36
- config: runConfig,
37
- mcp: runMcp,
38
- docs: runDocs,
39
- password: runPassword,
40
- };
41
-
42
- /** Returns true if a new command handled the invocation (skip legacy flow). */
43
- export async function runNewCommand(argv: string[], pkgRoot: string): Promise<boolean> {
44
- const args = argv.slice(2);
45
- const ctx: CommandContext = { argv, args, pkgRoot, cwd: process.cwd() };
46
-
47
- // Configure-only Pages→Actions: `--pages-actions` flag or `pages actions` verb.
48
- if (args.includes("--pages-actions") || (args[0] === "pages" && args[1] === "actions")) {
49
- await runPagesActions(ctx);
50
- return true;
51
- }
52
- // Full deploy: `pages deploy` (detect owner/repo, confirm, run the proven
53
- // push flow, print URL). Bare `pages`/`deploy` still fall through to legacy.
54
- if (args[0] === "pages" && args[1] === "deploy") {
55
- await runPagesDeploy(ctx);
56
- return true;
57
- }
58
- // Wipe the stored AI credentials config: `config clear`.
59
- if (args[0] === "config" && args[1] === "clear") {
60
- await runConfigClear(ctx);
61
- return true;
62
- }
63
-
64
- const handler = REGISTRY[args[0] ?? ""];
65
- if (!handler) return false;
66
- await handler(ctx);
67
- return true;
68
- }
69
-
70
- export const NEW_COMMAND_NAMES = Object.keys(REGISTRY).filter((n) => !n.startsWith("-"));
1
+ /**
2
+ * New-verb command layer (Phase 6). Intercepts the informational/utility
3
+ * commands that are NOT part of the legacy flag flow (version, doctor, provider,
4
+ * models, config, mcp, update) and routes them to thin handlers that consume
5
+ * @gitpagedocs/tools. Alias verbs (init, document, deploy, pages) are mapped in
6
+ * the parser and fall through to the legacy dispatch, so this returns false for
7
+ * them.
8
+ */
9
+ export interface CommandContext {
10
+ argv: string[];
11
+ args: string[];
12
+ pkgRoot: string;
13
+ cwd: string;
14
+ }
15
+
16
+ export type CommandHandler = (ctx: CommandContext) => Promise<void>;
17
+
18
+ import { runVersion, runDoctor, runUpdate } from "./diagnostics";
19
+ import { runProvider, runModels } from "./ai-info";
20
+ import { runConfig } from "./config-info";
21
+ import { runConfigClear } from "./config-clear";
22
+ import { runMcp } from "./mcp";
23
+ import { runDocs } from "./docs";
24
+ import { runPagesActions, runPagesDeploy } from "./pages";
25
+ import { runPassword } from "./password";
26
+
27
+ const REGISTRY: Record<string, CommandHandler> = {
28
+ version: runVersion,
29
+ "--version": runVersion,
30
+ "-v": runVersion,
31
+ doctor: runDoctor,
32
+ update: runUpdate,
33
+ provider: runProvider,
34
+ providers: runProvider,
35
+ models: runModels,
36
+ config: runConfig,
37
+ mcp: runMcp,
38
+ docs: runDocs,
39
+ password: runPassword,
40
+ };
41
+
42
+ /** Returns true if a new command handled the invocation (skip legacy flow). */
43
+ export async function runNewCommand(argv: string[], pkgRoot: string): Promise<boolean> {
44
+ const args = argv.slice(2);
45
+ const ctx: CommandContext = { argv, args, pkgRoot, cwd: process.cwd() };
46
+
47
+ // Configure-only Pages→Actions: `--pages-actions` flag or `pages actions` verb.
48
+ if (args.includes("--pages-actions") || (args[0] === "pages" && args[1] === "actions")) {
49
+ await runPagesActions(ctx);
50
+ return true;
51
+ }
52
+ // Full deploy: `pages deploy` (detect owner/repo, confirm, run the proven
53
+ // push flow, print URL). Bare `pages`/`deploy` still fall through to legacy.
54
+ if (args[0] === "pages" && args[1] === "deploy") {
55
+ await runPagesDeploy(ctx);
56
+ return true;
57
+ }
58
+ // Wipe the stored AI credentials config: `config clear`.
59
+ if (args[0] === "config" && args[1] === "clear") {
60
+ await runConfigClear(ctx);
61
+ return true;
62
+ }
63
+
64
+ const handler = REGISTRY[args[0] ?? ""];
65
+ if (!handler) return false;
66
+ await handler(ctx);
67
+ return true;
68
+ }
69
+
70
+ export const NEW_COMMAND_NAMES = Object.keys(REGISTRY).filter((n) => !n.startsWith("-"));
@@ -1,116 +1,124 @@
1
- #!/usr/bin/env node
2
-
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { printBanner, printCredits } from "./ui/banner";
6
- import { resolveOptions } from "./options/resolver";
7
- import { runNewCommand } from "./commands/run-command";
8
- import { dispatchMode } from "../application/use-cases/dispatch-mode";
9
- import type {
10
- CliRuntimeParams,
11
- ConfigOnlyRuntimePort,
12
- HomeRuntimePort,
13
- } from "../application/ports/cli-runtime-ports";
14
- // @ts-expect-error .mjs modules are runtime-only in this package.
15
- import { buildConfigArtifacts } from "../builders/config-orchestrator.mjs";
16
- // @ts-expect-error .mjs modules are runtime-only in this package.
17
- import { createThemeTemplate } from "../builders/theme-template.mjs";
18
- // @ts-expect-error .mjs modules are runtime-only in this package.
19
- import { LAYOUTS } from "../data/layouts.mjs";
20
- // @ts-expect-error .mjs modules are runtime-only in this package.
21
- import { executeConfigOnly } from "../application/config-only/handler.mjs";
22
- // @ts-expect-error .mjs modules are runtime-only in this package.
23
- import { executeHome } from "../application/home/handler.mjs";
24
- // @ts-expect-error .mjs modules are runtime-only in this package.
25
- import { createConfigOnlyRuntime } from "../infrastructure/config-only/runtime.mjs";
26
- // @ts-expect-error .mjs modules are runtime-only in this package.
27
- import { createHomeRuntime } from "../infrastructure/home/runtime.mjs";
28
-
29
- const scriptDir = path.dirname(fileURLToPath(import.meta.url));
30
- const root = process.cwd();
31
- // cli/ is the published package root (bin = cli/index.mjs). scriptDir is
32
- // cli/presentation, so pkgRoot = cli/ and the bundled prebuilt/ ships at
33
- // cli/prebuilt — works identically in-repo and when installed via npm.
34
- const pkgRoot = path.join(scriptDir, "..");
35
- const prebuiltDir = path.join(pkgRoot, "prebuilt");
36
-
37
- const params: CliRuntimeParams = {
38
- root,
39
- pkgRoot,
40
- prebuiltDir,
41
- buildConfigArtifacts,
42
- createThemeTemplate,
43
- layouts: LAYOUTS,
44
- };
45
-
46
- async function main(): Promise<void> {
47
- // `mcp start` owns stdout (the MCP stdio channel) — no banner/credits there.
48
- const stdoutOwnedByCommand = process.argv[2] === "mcp";
49
- if (!stdoutOwnedByCommand) printBanner();
50
-
51
- // New informational/utility commands (version, doctor, provider, models,
52
- // config, mcp, update) are handled before the legacy flag flow. Alias verbs
53
- // (init, document, deploy, pages) are mapped in the parser and fall through.
54
- if (await runNewCommand(process.argv, pkgRoot)) {
55
- if (!stdoutOwnedByCommand) printCredits();
56
- return;
57
- }
58
-
59
- const options = await resolveOptions(process.argv, process.env);
60
- const configOnlyRuntime = createConfigOnlyRuntime() as ConfigOnlyRuntimePort;
61
- const homeRuntime = createHomeRuntime() as HomeRuntimePort;
62
- await dispatchMode(options, params, {
63
- runConfigOnly: async (context) => {
64
- const safePrebuiltDir =
65
- typeof context.prebuiltDir === "string"
66
- ? context.prebuiltDir
67
- : path.join(String(context.pkgRoot ?? process.cwd()), "prebuilt");
68
- await executeConfigOnly(
69
- {
70
- ...context,
71
- prebuiltDir: safePrebuiltDir,
72
- },
73
- configOnlyRuntime,
74
- );
75
- },
76
- runHome: async (context) => {
77
- await executeHome(context, homeRuntime);
78
- },
79
- runAi: async (context) => {
80
- console.log("[gitpagedocs] Iniciando Módulo de IA na CLI...");
81
- const safePrebuiltDir =
82
- typeof context.prebuiltDir === "string"
83
- ? context.prebuiltDir
84
- : path.join(String(context.pkgRoot ?? process.cwd()), "prebuilt");
85
- // @ts-ignore
86
- const { runAiCliCommand } = await import("../ai/application/run-ai-cli-command.ts");
87
- const result = await runAiCliCommand({
88
- cwd: process.cwd(),
89
- onInfo: (message: string) => console.log(message),
90
- // Scaffold the base gitpagedocs/ structure before AI pages are wired in.
91
- onScaffold: async () => {
92
- await executeConfigOnly({ ...context, prebuiltDir: safePrebuiltDir }, configOnlyRuntime);
93
- },
94
- });
95
-
96
- if (result.summary.scannedFilesCount === 0) {
97
- console.log("[gitpagedocs:ai] Nenhum arquivo elegível foi encontrado nos paths informados.");
98
- return;
99
- }
100
-
101
- const pages = result.summary.pages ?? [];
102
- console.log(
103
- `\nProcesso completo. Páginas no padrão gitpagedocs: ${pages.join(", ") || "(nenhuma)"}`,
104
- );
105
- console.log(
106
- `[gitpagedocs:ai] ${result.summary.outputs.length} arquivos markdown gerados e conectados ao config.json da versão mais recente.`,
107
- );
108
- },
109
- });
110
- printCredits();
111
- }
112
-
113
- main().catch((err: unknown) => {
114
- console.error("Failed to create Git Page Docs scaffold.", err);
115
- process.exitCode = 1;
116
- });
1
+ #!/usr/bin/env node
2
+
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { printBanner, printCredits } from "./ui/banner";
6
+ import { resolveOptions } from "./options/resolver";
7
+ import { migrateLegacyLayoutsInteractive } from "./ui/layouts-prompts";
8
+ import { runNewCommand } from "./commands/run-command";
9
+ import { dispatchMode } from "../application/use-cases/dispatch-mode";
10
+ import type {
11
+ CliRuntimeParams,
12
+ ConfigOnlyRuntimePort,
13
+ HomeRuntimePort,
14
+ } from "../application/ports/cli-runtime-ports";
15
+ // @ts-expect-error .mjs modules are runtime-only in this package.
16
+ import { buildConfigArtifacts } from "../builders/config-orchestrator.mjs";
17
+ // @ts-expect-error .mjs modules are runtime-only in this package.
18
+ import { createThemeTemplate } from "../builders/theme-template.mjs";
19
+ // @ts-expect-error .mjs modules are runtime-only in this package.
20
+ import { LAYOUTS } from "../data/layouts.mjs";
21
+ // @ts-expect-error .mjs modules are runtime-only in this package.
22
+ import { executeConfigOnly } from "../application/config-only/handler.mjs";
23
+ // @ts-expect-error .mjs modules are runtime-only in this package.
24
+ import { executeHome } from "../application/home/handler.mjs";
25
+ // @ts-expect-error .mjs modules are runtime-only in this package.
26
+ import { createConfigOnlyRuntime } from "../infrastructure/config-only/runtime.mjs";
27
+ // @ts-expect-error .mjs modules are runtime-only in this package.
28
+ import { createHomeRuntime } from "../infrastructure/home/runtime.mjs";
29
+
30
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
31
+ const root = process.cwd();
32
+ // cli/ is the published package root (bin = cli/index.mjs). scriptDir is
33
+ // cli/presentation, so pkgRoot = cli/ and the bundled prebuilt/ ships at
34
+ // cli/prebuilt — works identically in-repo and when installed via npm.
35
+ const pkgRoot = path.join(scriptDir, "..");
36
+ const prebuiltDir = path.join(pkgRoot, "prebuilt");
37
+
38
+ const params: CliRuntimeParams = {
39
+ root,
40
+ pkgRoot,
41
+ prebuiltDir,
42
+ buildConfigArtifacts,
43
+ createThemeTemplate,
44
+ layouts: LAYOUTS,
45
+ };
46
+
47
+ async function main(): Promise<void> {
48
+ // `mcp start` owns stdout (the MCP stdio channel) — no banner/credits there.
49
+ const stdoutOwnedByCommand = process.argv[2] === "mcp";
50
+ if (!stdoutOwnedByCommand) printBanner();
51
+
52
+ // New informational/utility commands (version, doctor, provider, models,
53
+ // config, mcp, update) are handled before the legacy flag flow. Alias verbs
54
+ // (init, document, deploy, pages) are mapped in the parser and fall through.
55
+ if (await runNewCommand(process.argv, pkgRoot)) {
56
+ if (!stdoutOwnedByCommand) printCredits();
57
+ return;
58
+ }
59
+
60
+ const options = await resolveOptions(process.argv, process.env);
61
+
62
+ // Layouts moved out of <outputDir>/layouts/. Offer to relocate anything left
63
+ // behind before generating, so the config written next points at one folder.
64
+ if (options.mode === "config-only") {
65
+ await migrateLegacyLayoutsInteractive(root, options);
66
+ }
67
+
68
+ const configOnlyRuntime = createConfigOnlyRuntime() as ConfigOnlyRuntimePort;
69
+ const homeRuntime = createHomeRuntime() as HomeRuntimePort;
70
+ await dispatchMode(options, params, {
71
+ runConfigOnly: async (context) => {
72
+ const safePrebuiltDir =
73
+ typeof context.prebuiltDir === "string"
74
+ ? context.prebuiltDir
75
+ : path.join(String(context.pkgRoot ?? process.cwd()), "prebuilt");
76
+ await executeConfigOnly(
77
+ {
78
+ ...context,
79
+ prebuiltDir: safePrebuiltDir,
80
+ },
81
+ configOnlyRuntime,
82
+ );
83
+ },
84
+ runHome: async (context) => {
85
+ await executeHome(context, homeRuntime);
86
+ },
87
+ runAi: async (context) => {
88
+ console.log("[gitpagedocs] Iniciando Módulo de IA na CLI...");
89
+ const safePrebuiltDir =
90
+ typeof context.prebuiltDir === "string"
91
+ ? context.prebuiltDir
92
+ : path.join(String(context.pkgRoot ?? process.cwd()), "prebuilt");
93
+ // @ts-ignore
94
+ const { runAiCliCommand } = await import("../ai/application/run-ai-cli-command.ts");
95
+ const result = await runAiCliCommand({
96
+ cwd: process.cwd(),
97
+ onInfo: (message: string) => console.log(message),
98
+ // Scaffold the base gitpagedocs/ structure before AI pages are wired in.
99
+ onScaffold: async () => {
100
+ await executeConfigOnly({ ...context, prebuiltDir: safePrebuiltDir }, configOnlyRuntime);
101
+ },
102
+ });
103
+
104
+ if (result.summary.scannedFilesCount === 0) {
105
+ console.log("[gitpagedocs:ai] Nenhum arquivo elegível foi encontrado nos paths informados.");
106
+ return;
107
+ }
108
+
109
+ const pages = result.summary.pages ?? [];
110
+ console.log(
111
+ `\nProcesso completo. Páginas no padrão gitpagedocs: ${pages.join(", ") || "(nenhuma)"}`,
112
+ );
113
+ console.log(
114
+ `[gitpagedocs:ai] ${result.summary.outputs.length} arquivos markdown gerados e conectados ao config.json da versão mais recente.`,
115
+ );
116
+ },
117
+ });
118
+ printCredits();
119
+ }
120
+
121
+ main().catch((err: unknown) => {
122
+ console.error("Failed to create Git Page Docs scaffold.", err);
123
+ process.exitCode = 1;
124
+ });