@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
package/data/urls.mjs CHANGED
@@ -1,12 +1,12 @@
1
- /** Official layout URLs for git-page-docs repository.
2
- * The canonical home is the root `gitpagelayouts/` folder; the legacy
3
- * `gitpagedocs/layouts/` folder stays online for older deployments. */
4
-
5
- export const OFFICIAL_LAYOUTS_CONFIG_URL =
6
- "https://github.com/Vidigal-code/git-page-docs/blob/main/gitpagelayouts/layoutsConfig.json";
7
-
8
- export const OFFICIAL_LAYOUTS_TEMPLATES_URL =
9
- "https://github.com/Vidigal-code/git-page-docs/blob/main/gitpagelayouts/templates";
10
-
11
- export const LEGACY_OFFICIAL_LAYOUTS_CONFIG_URL =
12
- "https://github.com/Vidigal-code/git-page-docs/blob/main/gitpagedocs/layouts/layoutsConfig.json";
1
+ /** Official layout URLs for git-page-docs repository.
2
+ * The canonical home is the root `gitpagelayouts/` folder; the legacy
3
+ * `gitpagedocs/layouts/` folder stays online for older deployments. */
4
+
5
+ export const OFFICIAL_LAYOUTS_CONFIG_URL =
6
+ "https://github.com/Vidigal-code/git-page-docs/blob/main/gitpagelayouts/layoutsConfig.json";
7
+
8
+ export const OFFICIAL_LAYOUTS_TEMPLATES_URL =
9
+ "https://github.com/Vidigal-code/git-page-docs/blob/main/gitpagelayouts/templates";
10
+
11
+ export const LEGACY_OFFICIAL_LAYOUTS_CONFIG_URL =
12
+ "https://github.com/Vidigal-code/git-page-docs/blob/main/gitpagedocs/layouts/layoutsConfig.json";
@@ -1,18 +1,33 @@
1
- export type CliMode = "home" | "full" | "config-only" | "ai";
2
-
3
- export interface CliOptions {
4
- isBuild: boolean;
5
- isServe: boolean;
6
- mode: CliMode;
7
- aiCommand?: string;
8
- outputDir: string;
9
- useLocalLayoutConfig: boolean;
10
- shouldPush: boolean;
11
- githubOwner: string;
12
- githubRepo: string;
13
- docsPath: string;
14
- basePath: string;
15
- repositorySearch?: boolean;
16
- isInteractive: boolean;
17
- hasArgs: boolean;
18
- }
1
+ export type CliMode = "home" | "full" | "config-only" | "ai";
2
+
3
+ /**
4
+ * Values the user supplied explicitly on the command line. Interactive mode
5
+ * only asks for what is missing, so an explicit flag is never re-asked.
6
+ */
7
+ export interface CliExplicitFlags {
8
+ useLocalLayoutConfig: boolean;
9
+ layoutsDir: boolean;
10
+ githubOwner: boolean;
11
+ githubRepo: boolean;
12
+ outputDir: boolean;
13
+ }
14
+
15
+ export interface CliOptions {
16
+ isBuild: boolean;
17
+ isServe: boolean;
18
+ mode: CliMode;
19
+ aiCommand?: string;
20
+ outputDir: string;
21
+ /** Standalone layouts home (repo-relative); local layouts are generated here. */
22
+ layoutsDir: string;
23
+ useLocalLayoutConfig: boolean;
24
+ shouldPush: boolean;
25
+ githubOwner: string;
26
+ githubRepo: string;
27
+ docsPath: string;
28
+ basePath: string;
29
+ repositorySearch?: boolean;
30
+ isInteractive: boolean;
31
+ hasArgs: boolean;
32
+ explicit: CliExplicitFlags;
33
+ }
@@ -0,0 +1,15 @@
1
+ /** A planned move from the legacy layouts folder to the standalone home. */
2
+ export interface LayoutsMigrationPlan {
3
+ required: boolean;
4
+ from: string;
5
+ to: string;
6
+ files: string[];
7
+ overwrites: string[];
8
+ }
9
+
10
+ export declare function planLayoutsMigration(options: {
11
+ outputDir: string;
12
+ layoutsDir: string;
13
+ legacyFiles?: string[];
14
+ targetFiles?: string[];
15
+ }): LayoutsMigrationPlan;
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Legacy layouts migration — planning only.
3
+ *
4
+ * Deciding *what* should move is domain logic, so it stays free of prompts and
5
+ * filesystem writes: callers list the two folders, ask the user, and perform
6
+ * the move. That keeps the rule testable with plain arrays.
7
+ */
8
+ import { legacyLayoutsDir, normalizeLayoutsDir } from "../../contracts/layouts-paths.mjs";
9
+
10
+ /**
11
+ * @typedef {Object} LayoutsMigrationPlan
12
+ * @property {boolean} required True when the legacy folder holds files to move.
13
+ * @property {string} from Repo-relative legacy folder.
14
+ * @property {string} to Repo-relative destination folder.
15
+ * @property {string[]} files Paths relative to `from`, sorted.
16
+ * @property {string[]} overwrites Subset of `files` already present at `to`.
17
+ */
18
+
19
+ /**
20
+ * Plan the move from the legacy layouts folder to the standalone home.
21
+ *
22
+ * @param {Object} options
23
+ * @param {string} options.outputDir Docs output dir (owns the legacy folder).
24
+ * @param {string} options.layoutsDir Destination layouts folder.
25
+ * @param {string[]} [options.legacyFiles] Paths relative to the legacy folder.
26
+ * @param {string[]} [options.targetFiles] Paths relative to the destination folder.
27
+ * @returns {LayoutsMigrationPlan}
28
+ */
29
+ export function planLayoutsMigration(options = {}) {
30
+ const { outputDir, layoutsDir, legacyFiles, targetFiles } = options;
31
+
32
+ const from = legacyLayoutsDir(outputDir);
33
+ const to = normalizeLayoutsDir(layoutsDir);
34
+
35
+ const files = toSortedPaths(legacyFiles);
36
+ const present = new Set(toSortedPaths(targetFiles));
37
+
38
+ return {
39
+ required: files.length > 0 && from !== to,
40
+ from,
41
+ to,
42
+ files,
43
+ overwrites: files.filter((file) => present.has(file)),
44
+ };
45
+ }
46
+
47
+ /**
48
+ * Normalize, de-duplicate and sort a list of relative paths so a plan is
49
+ * deterministic regardless of directory-read order.
50
+ *
51
+ * @param {unknown} paths
52
+ * @returns {string[]}
53
+ */
54
+ function toSortedPaths(paths) {
55
+ if (!Array.isArray(paths)) return [];
56
+ const normalized = paths
57
+ .filter((entry) => typeof entry === "string" && entry.trim().length > 0)
58
+ .map((entry) => entry.replace(/[\\/]+/g, "/").replace(/^\/+/, ""));
59
+ return [...new Set(normalized)].sort();
60
+ }
@@ -1,4 +1,4 @@
1
- /** Constants for home distribution */
2
-
3
- export const STATIC_OUTPUT_DIR = "frontend/out";
4
- export const ARTIFACTS_DIR = "gitpagedocs";
1
+ /** Constants for home distribution */
2
+
3
+ export const STATIC_OUTPUT_DIR = "frontend/out";
4
+ export const ARTIFACTS_DIR = "gitpagedocs";
package/index.mjs CHANGED
@@ -1,38 +1,38 @@
1
1
  #!/usr/bin/env node
2
-
3
- import path from "node:path";
4
- import { fileURLToPath } from "node:url";
5
- import { spawnSync } from "node:child_process";
6
-
7
- const scriptPath = fileURLToPath(import.meta.url);
8
- const scriptDir = path.dirname(scriptPath);
9
- const tsEntry = path.join(scriptDir, "presentation", "index.ts");
10
-
11
- // Resolve tsx from THIS package's location, not the user's cwd. `node --import
12
- // tsx` would otherwise resolve the bare "tsx" specifier relative to the current
13
- // working directory, which fails when the CLI is installed globally and run
14
- // from a project that doesn't depend on tsx (ERR_MODULE_NOT_FOUND 'tsx').
15
- let tsxLoader = "tsx";
16
- try {
17
- tsxLoader = import.meta.resolve("tsx");
18
- } catch {
19
- // Older Node without a stable import.meta.resolve — fall back to the bare
20
- // specifier (works when tsx is resolvable from the cwd or globally).
21
- }
22
-
23
- const result = spawnSync(
24
- process.execPath,
25
- ["--import", tsxLoader, tsEntry, ...process.argv.slice(2)],
26
- {
27
- stdio: "inherit",
28
- cwd: process.cwd(),
29
- env: process.env,
30
- },
31
- );
32
-
33
- if (result.error) {
34
- console.error("[gitpagedocs] Failed to run TypeScript CLI runtime.", result.error);
35
- process.exitCode = 1;
36
- } else if (typeof result.status === "number" && result.status !== 0) {
37
- process.exitCode = result.status;
38
- }
2
+
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { spawnSync } from "node:child_process";
6
+
7
+ const scriptPath = fileURLToPath(import.meta.url);
8
+ const scriptDir = path.dirname(scriptPath);
9
+ const tsEntry = path.join(scriptDir, "presentation", "index.ts");
10
+
11
+ // Resolve tsx from THIS package's location, not the user's cwd. `node --import
12
+ // tsx` would otherwise resolve the bare "tsx" specifier relative to the current
13
+ // working directory, which fails when the CLI is installed globally and run
14
+ // from a project that doesn't depend on tsx (ERR_MODULE_NOT_FOUND 'tsx').
15
+ let tsxLoader = "tsx";
16
+ try {
17
+ tsxLoader = import.meta.resolve("tsx");
18
+ } catch {
19
+ // Older Node without a stable import.meta.resolve — fall back to the bare
20
+ // specifier (works when tsx is resolvable from the cwd or globally).
21
+ }
22
+
23
+ const result = spawnSync(
24
+ process.execPath,
25
+ ["--import", tsxLoader, tsEntry, ...process.argv.slice(2)],
26
+ {
27
+ stdio: "inherit",
28
+ cwd: process.cwd(),
29
+ env: process.env,
30
+ },
31
+ );
32
+
33
+ if (result.error) {
34
+ console.error("[gitpagedocs] Failed to run TypeScript CLI runtime.", result.error);
35
+ process.exitCode = 1;
36
+ } else if (typeof result.status === "number" && result.status !== 0) {
37
+ process.exitCode = result.status;
38
+ }
@@ -1,47 +1,47 @@
1
- import fs from "node:fs/promises";
2
- import { defaultConfigLoader } from "@gitpagedocs/tools";
3
-
4
- export interface DocsAccessConfig {
5
- enabled: boolean;
6
- publicKey: string;
7
- }
8
-
9
- /**
10
- * Reads and patches the generated gitpagedocs/config.json IN PLACE, preserving
11
- * every existing key (raw-JSON round-trip — it never reserializes through a typed
12
- * model that could drop unknown fields). Used by interactive commands that need
13
- * to persist a single value (e.g. the documentation password public key).
14
- */
15
- export class GitPageDocsConfigRepository {
16
- constructor(private readonly cwd: string = process.cwd()) {}
17
-
18
- /** Absolute path to the JSON config, or throws a friendly, actionable error. */
19
- async resolvePath(): Promise<string> {
20
- const resolved = await defaultConfigLoader.resolveConfigPath(this.cwd);
21
- if (!resolved) {
22
- throw new Error("gitpagedocs config.json not found. Run `gitpagedocs` first to generate it.");
23
- }
24
- if (!resolved.endsWith(".json")) {
25
- throw new Error(`Expected a JSON config to patch, found "${resolved}". Use a gitpagedocs/config.json.`);
26
- }
27
- return resolved;
28
- }
29
-
30
- /**
31
- * Set `site.docsAccess = { enabled, publicKey }`, leaving all other config keys
32
- * untouched. Returns the path that was written.
33
- */
34
- async patchDocsAccess(publicKey: string, enabled = true): Promise<string> {
35
- const configPath = await this.resolvePath();
36
- const raw = await fs.readFile(configPath, "utf-8");
37
- const config = JSON.parse(raw) as Record<string, unknown>;
38
- const site =
39
- config.site && typeof config.site === "object"
40
- ? (config.site as Record<string, unknown>)
41
- : {};
42
- site.docsAccess = { enabled, publicKey } satisfies DocsAccessConfig;
43
- config.site = site;
44
- await fs.writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
45
- return configPath;
46
- }
47
- }
1
+ import fs from "node:fs/promises";
2
+ import { defaultConfigLoader } from "@gitpagedocs/tools";
3
+
4
+ export interface DocsAccessConfig {
5
+ enabled: boolean;
6
+ publicKey: string;
7
+ }
8
+
9
+ /**
10
+ * Reads and patches the generated gitpagedocs/config.json IN PLACE, preserving
11
+ * every existing key (raw-JSON round-trip — it never reserializes through a typed
12
+ * model that could drop unknown fields). Used by interactive commands that need
13
+ * to persist a single value (e.g. the documentation password public key).
14
+ */
15
+ export class GitPageDocsConfigRepository {
16
+ constructor(private readonly cwd: string = process.cwd()) {}
17
+
18
+ /** Absolute path to the JSON config, or throws a friendly, actionable error. */
19
+ async resolvePath(): Promise<string> {
20
+ const resolved = await defaultConfigLoader.resolveConfigPath(this.cwd);
21
+ if (!resolved) {
22
+ throw new Error("gitpagedocs config.json not found. Run `gitpagedocs` first to generate it.");
23
+ }
24
+ if (!resolved.endsWith(".json")) {
25
+ throw new Error(`Expected a JSON config to patch, found "${resolved}". Use a gitpagedocs/config.json.`);
26
+ }
27
+ return resolved;
28
+ }
29
+
30
+ /**
31
+ * Set `site.docsAccess = { enabled, publicKey }`, leaving all other config keys
32
+ * untouched. Returns the path that was written.
33
+ */
34
+ async patchDocsAccess(publicKey: string, enabled = true): Promise<string> {
35
+ const configPath = await this.resolvePath();
36
+ const raw = await fs.readFile(configPath, "utf-8");
37
+ const config = JSON.parse(raw) as Record<string, unknown>;
38
+ const site =
39
+ config.site && typeof config.site === "object"
40
+ ? (config.site as Record<string, unknown>)
41
+ : {};
42
+ site.docsAccess = { enabled, publicKey } satisfies DocsAccessConfig;
43
+ config.site = site;
44
+ await fs.writeFile(configPath, `${JSON.stringify(config, null, 2)}\n`, "utf-8");
45
+ return configPath;
46
+ }
47
+ }
@@ -1,37 +1,37 @@
1
- import path from "node:path";
2
- import { cpSync, existsSync, readdirSync, rmSync } from "node:fs";
3
- import { execSync } from "node:child_process";
4
- import { writeConfigOnlyOutput, writeText } from "../../runtime/output.mjs";
5
- import { writeHomeFiles } from "../../home/home-file-writer.mjs";
6
- import { logInfo, logSuccess } from "../../ui/logger.mjs";
7
-
8
- function ensureDirEmpty(root, relativeDir) {
9
- const target = path.join(root, relativeDir);
10
- if (existsSync(target)) {
11
- rmSync(target, { recursive: true, force: true });
12
- }
13
- }
14
-
15
- function copyRecursive(src, dest) {
16
- cpSync(src, dest, { recursive: true, force: true });
17
- }
18
-
19
- function runNextBuild(root, env) {
20
- execSync("npx next build frontend", { cwd: root, env, stdio: "inherit" });
21
- }
22
-
23
- export function createHomeRuntime() {
24
- return {
25
- joinPath: (...parts) => path.join(...parts),
26
- ensureDirEmpty,
27
- copyRecursive,
28
- readDirNames: (absolutePath) => readdirSync(absolutePath),
29
- existsPath: existsSync,
30
- runNextBuild,
31
- writeConfigOnlyOutput,
32
- writeHomeFiles,
33
- writeText,
34
- logSuccess,
35
- logInfo,
36
- };
37
- }
1
+ import path from "node:path";
2
+ import { cpSync, existsSync, readdirSync, rmSync } from "node:fs";
3
+ import { execSync } from "node:child_process";
4
+ import { writeConfigOnlyOutput, writeText } from "../../runtime/output.mjs";
5
+ import { writeHomeFiles } from "../../home/home-file-writer.mjs";
6
+ import { logInfo, logSuccess } from "../../ui/logger.mjs";
7
+
8
+ function ensureDirEmpty(root, relativeDir) {
9
+ const target = path.join(root, relativeDir);
10
+ if (existsSync(target)) {
11
+ rmSync(target, { recursive: true, force: true });
12
+ }
13
+ }
14
+
15
+ function copyRecursive(src, dest) {
16
+ cpSync(src, dest, { recursive: true, force: true });
17
+ }
18
+
19
+ function runNextBuild(root, env) {
20
+ execSync("npx next build frontend", { cwd: root, env, stdio: "inherit" });
21
+ }
22
+
23
+ export function createHomeRuntime() {
24
+ return {
25
+ joinPath: (...parts) => path.join(...parts),
26
+ ensureDirEmpty,
27
+ copyRecursive,
28
+ readDirNames: (absolutePath) => readdirSync(absolutePath),
29
+ existsPath: existsSync,
30
+ runNextBuild,
31
+ writeConfigOnlyOutput,
32
+ writeHomeFiles,
33
+ writeText,
34
+ logSuccess,
35
+ logInfo,
36
+ };
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitpagedocs/cli",
3
- "version": "1.1.61",
3
+ "version": "1.1.63",
4
4
  "description": "CLI that scaffolds and maintains gitpagedocs documentation, generates docs with AI, configures GitHub Pages, and runs the MCP server.",
5
5
  "bin": {
6
6
  "gitpagedocs": "index.mjs"
@@ -29,8 +29,8 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@clack/prompts": "^1.5.1",
32
- "@gitpagedocs/mcp": "^1.1.61",
33
- "@gitpagedocs/tools": "^1.1.61",
32
+ "@gitpagedocs/mcp": "^1.1.63",
33
+ "@gitpagedocs/tools": "^1.1.63",
34
34
  "tsx": "^4.21.0"
35
35
  },
36
36
  "repository": {
@@ -1,57 +1,57 @@
1
- import { PROVIDER_CATALOG, ALL_PROVIDER_IDS, createModelRegistry, type AiProviderId } from "@gitpagedocs/tools";
2
- import type { CommandContext } from "./run-command";
3
-
4
- function capsLabel(caps: { streaming: boolean; vision: boolean; audio: boolean }): string {
5
- const parts: string[] = [];
6
- if (caps.streaming) parts.push("stream");
7
- if (caps.vision) parts.push("vision");
8
- if (caps.audio) parts.push("audio");
9
- return parts.join(", ") || "text";
10
- }
11
-
12
- /** `gitpagedocs provider [id]` — list providers or show one provider's detail. */
13
- export async function runProvider(ctx: CommandContext): Promise<void> {
14
- const requested = ctx.args[1] as AiProviderId | undefined;
15
- if (requested && PROVIDER_CATALOG[requested]) {
16
- const spec = PROVIDER_CATALOG[requested];
17
- // eslint-disable-next-line no-console
18
- console.log(
19
- `\n ${spec.label} (${spec.id})\n` +
20
- ` default model : ${spec.defaultModel}\n` +
21
- ` capabilities : ${capsLabel(spec.capabilities)}\n` +
22
- ` base url : ${spec.baseUrl || "(user-provided)"}\n` +
23
- ` models : ${spec.models.map((m) => m.id).join(", ")}\n`,
24
- );
25
- return;
26
- }
27
-
28
- // eslint-disable-next-line no-console
29
- console.log(`\n AI providers (${ALL_PROVIDER_IDS.length}):\n`);
30
- for (const id of ALL_PROVIDER_IDS) {
31
- const spec = PROVIDER_CATALOG[id];
32
- // eslint-disable-next-line no-console
33
- console.log(` ${id.padEnd(14)} ${spec.label.padEnd(18)} ${spec.defaultModel}`);
34
- }
35
- // eslint-disable-next-line no-console
36
- console.log("\n Detail: gitpagedocs provider <id>\n");
37
- }
38
-
39
- /** `gitpagedocs models [provider]` — list models for one or all providers. */
40
- export async function runModels(ctx: CommandContext): Promise<void> {
41
- const models = createModelRegistry();
42
- const requested = ctx.args[1] as AiProviderId | undefined;
43
- const ids = requested && PROVIDER_CATALOG[requested] ? [requested] : ALL_PROVIDER_IDS;
44
- // eslint-disable-next-line no-console
45
- console.log("");
46
- for (const id of ids) {
47
- const list = models.list(id);
48
- // eslint-disable-next-line no-console
49
- console.log(` ${PROVIDER_CATALOG[id].label} (${id}):`);
50
- for (const m of list) {
51
- // eslint-disable-next-line no-console
52
- console.log(` - ${m.id}${m.id === PROVIDER_CATALOG[id].defaultModel ? " (default)" : ""}`);
53
- }
54
- }
55
- // eslint-disable-next-line no-console
56
- console.log("");
57
- }
1
+ import { PROVIDER_CATALOG, ALL_PROVIDER_IDS, createModelRegistry, type AiProviderId } from "@gitpagedocs/tools";
2
+ import type { CommandContext } from "./run-command";
3
+
4
+ function capsLabel(caps: { streaming: boolean; vision: boolean; audio: boolean }): string {
5
+ const parts: string[] = [];
6
+ if (caps.streaming) parts.push("stream");
7
+ if (caps.vision) parts.push("vision");
8
+ if (caps.audio) parts.push("audio");
9
+ return parts.join(", ") || "text";
10
+ }
11
+
12
+ /** `gitpagedocs provider [id]` — list providers or show one provider's detail. */
13
+ export async function runProvider(ctx: CommandContext): Promise<void> {
14
+ const requested = ctx.args[1] as AiProviderId | undefined;
15
+ if (requested && PROVIDER_CATALOG[requested]) {
16
+ const spec = PROVIDER_CATALOG[requested];
17
+ // eslint-disable-next-line no-console
18
+ console.log(
19
+ `\n ${spec.label} (${spec.id})\n` +
20
+ ` default model : ${spec.defaultModel}\n` +
21
+ ` capabilities : ${capsLabel(spec.capabilities)}\n` +
22
+ ` base url : ${spec.baseUrl || "(user-provided)"}\n` +
23
+ ` models : ${spec.models.map((m) => m.id).join(", ")}\n`,
24
+ );
25
+ return;
26
+ }
27
+
28
+ // eslint-disable-next-line no-console
29
+ console.log(`\n AI providers (${ALL_PROVIDER_IDS.length}):\n`);
30
+ for (const id of ALL_PROVIDER_IDS) {
31
+ const spec = PROVIDER_CATALOG[id];
32
+ // eslint-disable-next-line no-console
33
+ console.log(` ${id.padEnd(14)} ${spec.label.padEnd(18)} ${spec.defaultModel}`);
34
+ }
35
+ // eslint-disable-next-line no-console
36
+ console.log("\n Detail: gitpagedocs provider <id>\n");
37
+ }
38
+
39
+ /** `gitpagedocs models [provider]` — list models for one or all providers. */
40
+ export async function runModels(ctx: CommandContext): Promise<void> {
41
+ const models = createModelRegistry();
42
+ const requested = ctx.args[1] as AiProviderId | undefined;
43
+ const ids = requested && PROVIDER_CATALOG[requested] ? [requested] : ALL_PROVIDER_IDS;
44
+ // eslint-disable-next-line no-console
45
+ console.log("");
46
+ for (const id of ids) {
47
+ const list = models.list(id);
48
+ // eslint-disable-next-line no-console
49
+ console.log(` ${PROVIDER_CATALOG[id].label} (${id}):`);
50
+ for (const m of list) {
51
+ // eslint-disable-next-line no-console
52
+ console.log(` - ${m.id}${m.id === PROVIDER_CATALOG[id].defaultModel ? " (default)" : ""}`);
53
+ }
54
+ }
55
+ // eslint-disable-next-line no-console
56
+ console.log("");
57
+ }
@@ -1,23 +1,23 @@
1
- import { AiConfigFileRepository } from "../../ai/infrastructure/ai-config-file";
2
- import type { CommandContext } from "./run-command";
3
-
4
- /**
5
- * `gitpagedocs config clear` — delete the stored `.gitpagedocsconfig` from the
6
- * per-user config directory and any legacy repo-root copy, wiping the saved AI
7
- * credentials (API key, provider, scan paths).
8
- */
9
- export async function runConfigClear(ctx: CommandContext): Promise<void> {
10
- const repository = new AiConfigFileRepository({ cwd: ctx.cwd });
11
- const removed = await repository.clear();
12
-
13
- if (!removed.length) {
14
- // eslint-disable-next-line no-console
15
- console.log("\n No stored .gitpagedocsconfig found - nothing to clear.\n");
16
- return;
17
- }
18
-
19
- // eslint-disable-next-line no-console
20
- console.log(
21
- ["", " Stored AI configuration removed (credentials wiped):", ...removed.map((p) => ` - ${p}`), ""].join("\n"),
22
- );
23
- }
1
+ import { AiConfigFileRepository } from "../../ai/infrastructure/ai-config-file";
2
+ import type { CommandContext } from "./run-command";
3
+
4
+ /**
5
+ * `gitpagedocs config clear` — delete the stored `.gitpagedocsconfig` from the
6
+ * per-user config directory and any legacy repo-root copy, wiping the saved AI
7
+ * credentials (API key, provider, scan paths).
8
+ */
9
+ export async function runConfigClear(ctx: CommandContext): Promise<void> {
10
+ const repository = new AiConfigFileRepository({ cwd: ctx.cwd });
11
+ const removed = await repository.clear();
12
+
13
+ if (!removed.length) {
14
+ // eslint-disable-next-line no-console
15
+ console.log("\n No stored .gitpagedocsconfig found - nothing to clear.\n");
16
+ return;
17
+ }
18
+
19
+ // eslint-disable-next-line no-console
20
+ console.log(
21
+ ["", " Stored AI configuration removed (credentials wiped):", ...removed.map((p) => ` - ${p}`), ""].join("\n"),
22
+ );
23
+ }
@@ -1,24 +1,24 @@
1
- import path from "node:path";
2
- import { defaultConfigLoader, isAppError } from "@gitpagedocs/tools";
3
- import type { CommandContext } from "./run-command";
4
-
5
- /** `gitpagedocs config` — resolve and summarize the active gitpagedocs config. */
6
- export async function runConfig(ctx: CommandContext): Promise<void> {
7
- try {
8
- const { config, sourcePath, extension } = await defaultConfigLoader.loadGitPageDocsConfig(ctx.cwd);
9
- const site = (config as { site?: Record<string, unknown> }).site ?? {};
10
- // eslint-disable-next-line no-console
11
- console.log(
12
- `\n Config: ${path.relative(ctx.cwd, sourcePath)} (${extension})\n` +
13
- ` site name : ${String(site.name ?? "—")}\n` +
14
- ` default language : ${String(site.defaultLanguage ?? "—")}\n` +
15
- ` languages : ${
16
- Array.isArray(site.supportedLanguages) ? (site.supportedLanguages as string[]).join(", ") : "—"
17
- }\n`,
18
- );
19
- } catch (error) {
20
- const message = isAppError(error) ? error.message : String(error);
21
- // eslint-disable-next-line no-console
22
- console.log(`\n No usable config found: ${message}\n Run \`gitpagedocs init\` to generate one.\n`);
23
- }
24
- }
1
+ import path from "node:path";
2
+ import { defaultConfigLoader, isAppError } from "@gitpagedocs/tools";
3
+ import type { CommandContext } from "./run-command";
4
+
5
+ /** `gitpagedocs config` — resolve and summarize the active gitpagedocs config. */
6
+ export async function runConfig(ctx: CommandContext): Promise<void> {
7
+ try {
8
+ const { config, sourcePath, extension } = await defaultConfigLoader.loadGitPageDocsConfig(ctx.cwd);
9
+ const site = (config as { site?: Record<string, unknown> }).site ?? {};
10
+ // eslint-disable-next-line no-console
11
+ console.log(
12
+ `\n Config: ${path.relative(ctx.cwd, sourcePath)} (${extension})\n` +
13
+ ` site name : ${String(site.name ?? "—")}\n` +
14
+ ` default language : ${String(site.defaultLanguage ?? "—")}\n` +
15
+ ` languages : ${
16
+ Array.isArray(site.supportedLanguages) ? (site.supportedLanguages as string[]).join(", ") : "—"
17
+ }\n`,
18
+ );
19
+ } catch (error) {
20
+ const message = isAppError(error) ? error.message : String(error);
21
+ // eslint-disable-next-line no-console
22
+ console.log(`\n No usable config found: ${message}\n Run \`gitpagedocs init\` to generate one.\n`);
23
+ }
24
+ }