@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
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
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
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
|
+
}
|
package/home/constants.mjs
CHANGED
|
@@ -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.
|
|
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.
|
|
33
|
-
"@gitpagedocs/tools": "^1.1.
|
|
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
|
+
}
|