@gitpagedocs/cli 1.1.62 → 1.1.64

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 (59) hide show
  1. package/README.md +193 -193
  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/ports/cli-runtime-ports.ts +91 -91
  16. package/application/report/config-only-reporter.mjs +64 -64
  17. package/application/use-cases/dispatch-mode.ts +18 -18
  18. package/builders/config-orchestrator.mjs +34 -34
  19. package/builders/project-links.mjs +50 -50
  20. package/builders/root-config-builder.mjs +61 -61
  21. package/builders/route-builders.mjs +136 -136
  22. package/builders/theme-template.mjs +76 -76
  23. package/builders/version-config-builder.mjs +186 -186
  24. package/content/docs-en.mjs +549 -549
  25. package/content/docs-es.mjs +462 -462
  26. package/content/docs-pt.mjs +462 -462
  27. package/contracts/doc-versions.mjs +3 -3
  28. package/data/default-site-config.mjs +321 -321
  29. package/data/i18n-langmenu.mjs +347 -347
  30. package/data/layouts.mjs +436 -436
  31. package/data/path-mappings.mjs +26 -26
  32. package/data/route-metas.mjs +93 -93
  33. package/data/theme-colors.mjs +443 -443
  34. package/data/urls.mjs +12 -12
  35. package/domain/models/cli-options.ts +33 -33
  36. package/home/constants.mjs +4 -4
  37. package/index.mjs +37 -37
  38. package/infrastructure/gitpagedocs-config-file.ts +47 -47
  39. package/infrastructure/home/runtime.mjs +37 -37
  40. package/package.json +3 -3
  41. package/presentation/commands/ai-info.ts +57 -57
  42. package/presentation/commands/config-clear.ts +23 -23
  43. package/presentation/commands/config-info.ts +24 -24
  44. package/presentation/commands/diagnostics.ts +164 -164
  45. package/presentation/commands/docs.ts +37 -37
  46. package/presentation/commands/mcp.ts +20 -20
  47. package/presentation/commands/pages.ts +101 -101
  48. package/presentation/commands/password.ts +62 -62
  49. package/presentation/commands/run-command.ts +70 -70
  50. package/presentation/index.ts +124 -124
  51. package/presentation/options/parser.ts +119 -119
  52. package/presentation/options/resolver.ts +46 -46
  53. package/presentation/ui/clack.ts +91 -91
  54. package/presentation/ui/prompts.ts +146 -146
  55. package/runtime/git-ops.mjs +110 -110
  56. package/runtime/output.mjs +159 -159
  57. package/runtime/workflow.mjs +129 -129
  58. package/start.mjs +12 -12
  59. package/ui/logger.mjs +9 -9
@@ -1,164 +1,164 @@
1
- import path from "node:path";
2
- import { readFileSync, existsSync } from "node:fs";
3
- import { execSync } from "node:child_process";
4
- import { defaultConfigLoader } from "@gitpagedocs/tools";
5
- import type { CommandContext } from "./run-command";
6
-
7
- function readVersion(pkgRoot: string): string {
8
- try {
9
- const pkg = JSON.parse(readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
10
- return String(pkg.version ?? "unknown");
11
- } catch {
12
- return "unknown";
13
- }
14
- }
15
-
16
- export async function runVersion(ctx: CommandContext): Promise<void> {
17
- // eslint-disable-next-line no-console
18
- console.log(`gitpagedocs ${readVersion(ctx.pkgRoot)} (node ${process.version})`);
19
- }
20
-
21
- function probe(label: string, command: string): { label: string; ok: boolean; detail: string } {
22
- try {
23
- const out = execSync(command, { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
24
- return { label, ok: true, detail: out.split("\n")[0] };
25
- } catch {
26
- return { label, ok: false, detail: "not found" };
27
- }
28
- }
29
-
30
- export async function runDoctor(ctx: CommandContext): Promise<void> {
31
- const checks: Array<{ label: string; ok: boolean; detail: string }> = [];
32
- checks.push({ label: "node", ok: true, detail: process.version });
33
- checks.push(probe("git", "git --version"));
34
- checks.push(probe("gh (GitHub CLI)", "gh --version"));
35
- checks.push(probe("pnpm", "pnpm --version"));
36
-
37
- const configPath = await defaultConfigLoader.resolveConfigPath(ctx.cwd);
38
- checks.push({
39
- label: "gitpagedocs config",
40
- ok: Boolean(configPath),
41
- detail: configPath ? path.relative(ctx.cwd, configPath) : "not found (run `gitpagedocs init`)",
42
- });
43
- checks.push({
44
- label: "gitpagedocs/ directory",
45
- ok: existsSync(path.join(ctx.cwd, "gitpagedocs")),
46
- detail: existsSync(path.join(ctx.cwd, "gitpagedocs")) ? "present" : "missing",
47
- });
48
-
49
- // eslint-disable-next-line no-console
50
- console.log("\n gitpagedocs doctor\n");
51
- for (const c of checks) {
52
- // eslint-disable-next-line no-console
53
- console.log(` ${c.ok ? "[ok]" : "[x] "} ${c.label.padEnd(22)} ${c.detail}`);
54
- }
55
- const failed = checks.filter((c) => !c.ok && c.label !== "gh (GitHub CLI)").length;
56
- // eslint-disable-next-line no-console
57
- console.log(`\n ${failed === 0 ? "All required checks passed." : `${failed} check(s) need attention.`}\n`);
58
- }
59
-
60
- /** Used only when package.json is unreadable — the CLI's published name. */
61
- const FALLBACK_PACKAGE = "@gitpagedocs/cli";
62
- /** The bin this package installs; shown alongside the package name. */
63
- const BIN_NAME = "gitpagedocs";
64
-
65
- interface PackageIdentity {
66
- name: string;
67
- version: string;
68
- }
69
-
70
- /**
71
- * Read the identity from the installed package.json rather than hardcoding it,
72
- * so the hint always names the package the user actually has. A hardcoded name
73
- * is how `update` ended up advertising an unpublished package.
74
- */
75
- function readPackageIdentity(pkgRoot: string): PackageIdentity {
76
- try {
77
- const pkg = JSON.parse(readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
78
- const name = typeof pkg.name === "string" && pkg.name.length > 0 ? pkg.name : FALLBACK_PACKAGE;
79
- return { name, version: String(pkg.version ?? "unknown") };
80
- } catch {
81
- return { name: FALLBACK_PACKAGE, version: "unknown" };
82
- }
83
- }
84
-
85
- type RegistryLookup =
86
- | { status: "ok"; latest: string }
87
- | { status: "missing" }
88
- | { status: "unreachable" };
89
-
90
- function registryBase(): string {
91
- const configured = process.env.npm_config_registry || "https://registry.npmjs.org";
92
- return configured.endsWith("/") ? configured.slice(0, -1) : configured;
93
- }
94
-
95
- /** Resolve the dist-tag `latest` for a package. Never throws. */
96
- async function fetchLatest(name: string, timeoutMs = 6000): Promise<RegistryLookup> {
97
- const encoded = name.split("/").map(encodeURIComponent).join("/");
98
- try {
99
- const response = await fetch(`${registryBase()}/${encoded}/latest`, {
100
- signal: AbortSignal.timeout(timeoutMs),
101
- });
102
- if (response.status === 404) return { status: "missing" };
103
- if (!response.ok) return { status: "unreachable" };
104
- const body = (await response.json()) as { version?: unknown };
105
- if (typeof body.version === "string" && body.version.length > 0) {
106
- return { status: "ok", latest: body.version };
107
- }
108
- return { status: "unreachable" };
109
- } catch {
110
- return { status: "unreachable" };
111
- }
112
- }
113
-
114
- /** Numeric version compare, prerelease suffix ignored. */
115
- function compareVersions(a: string, b: string): number {
116
- const parts = (value: string): number[] =>
117
- value.split("-")[0].split(".").map((piece) => Number.parseInt(piece, 10) || 0);
118
- const left = parts(a);
119
- const right = parts(b);
120
- for (let i = 0; i < Math.max(left.length, right.length); i += 1) {
121
- const diff = (left[i] ?? 0) - (right[i] ?? 0);
122
- if (diff !== 0) return diff < 0 ? -1 : 1;
123
- }
124
- return 0;
125
- }
126
-
127
- export async function runUpdate(ctx: CommandContext): Promise<void> {
128
- const { name, version } = readPackageIdentity(ctx.pkgRoot);
129
- const lookup = await fetchLatest(name);
130
- const label = name === BIN_NAME ? `${BIN_NAME} ${version}` : `${BIN_NAME} ${version} (${name})`;
131
- const lines = ["", ` Installed: ${label}`];
132
-
133
- if (lookup.status === "ok") {
134
- lines.push(` Latest: ${lookup.latest}`);
135
- } else if (lookup.status === "missing") {
136
- lines.push(` Latest: unavailable — the registry has no published ${name}`);
137
- } else {
138
- lines.push(" Latest: unknown — could not reach the npm registry");
139
- }
140
-
141
- if (lookup.status === "missing") {
142
- lines.push(
143
- "",
144
- " Nothing can be installed under that name. If the package was renamed",
145
- " or unpublished, check the current one:",
146
- " https://www.npmjs.com/package/@gitpagedocs/cli",
147
- );
148
- } else if (lookup.status === "ok" && compareVersions(version, lookup.latest) >= 0) {
149
- lines.push("", " Already on the latest published version.");
150
- } else {
151
- const target = lookup.status === "ok" ? lookup.latest : "latest";
152
- lines.push(
153
- "",
154
- " To update the global CLI:",
155
- ` npm i -g ${name}@${target}`,
156
- " Or, in a project:",
157
- ` pnpm add -D ${name}@${target}`,
158
- );
159
- }
160
-
161
- lines.push("");
162
- // eslint-disable-next-line no-console
163
- console.log(lines.join("\n"));
164
- }
1
+ import path from "node:path";
2
+ import { readFileSync, existsSync } from "node:fs";
3
+ import { execSync } from "node:child_process";
4
+ import { defaultConfigLoader } from "@gitpagedocs/tools";
5
+ import type { CommandContext } from "./run-command";
6
+
7
+ function readVersion(pkgRoot: string): string {
8
+ try {
9
+ const pkg = JSON.parse(readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
10
+ return String(pkg.version ?? "unknown");
11
+ } catch {
12
+ return "unknown";
13
+ }
14
+ }
15
+
16
+ export async function runVersion(ctx: CommandContext): Promise<void> {
17
+ // eslint-disable-next-line no-console
18
+ console.log(`gitpagedocs ${readVersion(ctx.pkgRoot)} (node ${process.version})`);
19
+ }
20
+
21
+ function probe(label: string, command: string): { label: string; ok: boolean; detail: string } {
22
+ try {
23
+ const out = execSync(command, { stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
24
+ return { label, ok: true, detail: out.split("\n")[0] };
25
+ } catch {
26
+ return { label, ok: false, detail: "not found" };
27
+ }
28
+ }
29
+
30
+ export async function runDoctor(ctx: CommandContext): Promise<void> {
31
+ const checks: Array<{ label: string; ok: boolean; detail: string }> = [];
32
+ checks.push({ label: "node", ok: true, detail: process.version });
33
+ checks.push(probe("git", "git --version"));
34
+ checks.push(probe("gh (GitHub CLI)", "gh --version"));
35
+ checks.push(probe("pnpm", "pnpm --version"));
36
+
37
+ const configPath = await defaultConfigLoader.resolveConfigPath(ctx.cwd);
38
+ checks.push({
39
+ label: "gitpagedocs config",
40
+ ok: Boolean(configPath),
41
+ detail: configPath ? path.relative(ctx.cwd, configPath) : "not found (run `gitpagedocs init`)",
42
+ });
43
+ checks.push({
44
+ label: "gitpagedocs/ directory",
45
+ ok: existsSync(path.join(ctx.cwd, "gitpagedocs")),
46
+ detail: existsSync(path.join(ctx.cwd, "gitpagedocs")) ? "present" : "missing",
47
+ });
48
+
49
+ // eslint-disable-next-line no-console
50
+ console.log("\n gitpagedocs doctor\n");
51
+ for (const c of checks) {
52
+ // eslint-disable-next-line no-console
53
+ console.log(` ${c.ok ? "[ok]" : "[x] "} ${c.label.padEnd(22)} ${c.detail}`);
54
+ }
55
+ const failed = checks.filter((c) => !c.ok && c.label !== "gh (GitHub CLI)").length;
56
+ // eslint-disable-next-line no-console
57
+ console.log(`\n ${failed === 0 ? "All required checks passed." : `${failed} check(s) need attention.`}\n`);
58
+ }
59
+
60
+ /** Used only when package.json is unreadable — the CLI's published name. */
61
+ const FALLBACK_PACKAGE = "@gitpagedocs/cli";
62
+ /** The bin this package installs; shown alongside the package name. */
63
+ const BIN_NAME = "gitpagedocs";
64
+
65
+ interface PackageIdentity {
66
+ name: string;
67
+ version: string;
68
+ }
69
+
70
+ /**
71
+ * Read the identity from the installed package.json rather than hardcoding it,
72
+ * so the hint always names the package the user actually has. A hardcoded name
73
+ * is how `update` ended up advertising an unpublished package.
74
+ */
75
+ function readPackageIdentity(pkgRoot: string): PackageIdentity {
76
+ try {
77
+ const pkg = JSON.parse(readFileSync(path.join(pkgRoot, "package.json"), "utf8"));
78
+ const name = typeof pkg.name === "string" && pkg.name.length > 0 ? pkg.name : FALLBACK_PACKAGE;
79
+ return { name, version: String(pkg.version ?? "unknown") };
80
+ } catch {
81
+ return { name: FALLBACK_PACKAGE, version: "unknown" };
82
+ }
83
+ }
84
+
85
+ type RegistryLookup =
86
+ | { status: "ok"; latest: string }
87
+ | { status: "missing" }
88
+ | { status: "unreachable" };
89
+
90
+ function registryBase(): string {
91
+ const configured = process.env.npm_config_registry || "https://registry.npmjs.org";
92
+ return configured.endsWith("/") ? configured.slice(0, -1) : configured;
93
+ }
94
+
95
+ /** Resolve the dist-tag `latest` for a package. Never throws. */
96
+ async function fetchLatest(name: string, timeoutMs = 6000): Promise<RegistryLookup> {
97
+ const encoded = name.split("/").map(encodeURIComponent).join("/");
98
+ try {
99
+ const response = await fetch(`${registryBase()}/${encoded}/latest`, {
100
+ signal: AbortSignal.timeout(timeoutMs),
101
+ });
102
+ if (response.status === 404) return { status: "missing" };
103
+ if (!response.ok) return { status: "unreachable" };
104
+ const body = (await response.json()) as { version?: unknown };
105
+ if (typeof body.version === "string" && body.version.length > 0) {
106
+ return { status: "ok", latest: body.version };
107
+ }
108
+ return { status: "unreachable" };
109
+ } catch {
110
+ return { status: "unreachable" };
111
+ }
112
+ }
113
+
114
+ /** Numeric version compare, prerelease suffix ignored. */
115
+ function compareVersions(a: string, b: string): number {
116
+ const parts = (value: string): number[] =>
117
+ value.split("-")[0].split(".").map((piece) => Number.parseInt(piece, 10) || 0);
118
+ const left = parts(a);
119
+ const right = parts(b);
120
+ for (let i = 0; i < Math.max(left.length, right.length); i += 1) {
121
+ const diff = (left[i] ?? 0) - (right[i] ?? 0);
122
+ if (diff !== 0) return diff < 0 ? -1 : 1;
123
+ }
124
+ return 0;
125
+ }
126
+
127
+ export async function runUpdate(ctx: CommandContext): Promise<void> {
128
+ const { name, version } = readPackageIdentity(ctx.pkgRoot);
129
+ const lookup = await fetchLatest(name);
130
+ const label = name === BIN_NAME ? `${BIN_NAME} ${version}` : `${BIN_NAME} ${version} (${name})`;
131
+ const lines = ["", ` Installed: ${label}`];
132
+
133
+ if (lookup.status === "ok") {
134
+ lines.push(` Latest: ${lookup.latest}`);
135
+ } else if (lookup.status === "missing") {
136
+ lines.push(` Latest: unavailable — the registry has no published ${name}`);
137
+ } else {
138
+ lines.push(" Latest: unknown — could not reach the npm registry");
139
+ }
140
+
141
+ if (lookup.status === "missing") {
142
+ lines.push(
143
+ "",
144
+ " Nothing can be installed under that name. If the package was renamed",
145
+ " or unpublished, check the current one:",
146
+ " https://www.npmjs.com/package/@gitpagedocs/cli",
147
+ );
148
+ } else if (lookup.status === "ok" && compareVersions(version, lookup.latest) >= 0) {
149
+ lines.push("", " Already on the latest published version.");
150
+ } else {
151
+ const target = lookup.status === "ok" ? lookup.latest : "latest";
152
+ lines.push(
153
+ "",
154
+ " To update the global CLI:",
155
+ ` npm i -g ${name}@${target}`,
156
+ " Or, in a project:",
157
+ ` pnpm add -D ${name}@${target}`,
158
+ );
159
+ }
160
+
161
+ lines.push("");
162
+ // eslint-disable-next-line no-console
163
+ console.log(lines.join("\n"));
164
+ }
@@ -1,37 +1,37 @@
1
- import {
2
- FileService,
3
- DocUpdater,
4
- providersSection,
5
- cliCommandsSection,
6
- devWorkflowSection,
7
- securityNoteSection,
8
- CLI_COMMANDS,
9
- } from "@gitpagedocs/tools";
10
- import type { CommandContext } from "./run-command";
11
-
12
- /**
13
- * `gitpagedocs docs` — refresh the managed regions of the standard docs files
14
- * with deterministic content. Idempotent and marker-bounded: manual content
15
- * outside `<!-- gitpagedocs:start/end -->` is preserved; missing files are
16
- * created. Covers README, CONTRIBUTING and SECURITY (master-spec docs set).
17
- */
18
- export async function runDocs(ctx: CommandContext): Promise<void> {
19
- const updater = new DocUpdater(new FileService(ctx.cwd));
20
-
21
- const updates = [
22
- { path: "README.md", generated: `${providersSection()}\n\n${cliCommandsSection(CLI_COMMANDS)}` },
23
- { path: "CONTRIBUTING.md", generated: `${devWorkflowSection()}\n\n${cliCommandsSection(CLI_COMMANDS)}` },
24
- { path: "SECURITY.md", generated: securityNoteSection() },
25
- ];
26
-
27
- const results = await updater.updateManagedFiles(updates);
28
- // eslint-disable-next-line no-console
29
- console.log("");
30
- for (const r of results) {
31
- const state = r.changed ? (r.replaced ? "managed region updated" : "managed region added") : "already up to date";
32
- // eslint-disable-next-line no-console
33
- console.log(` ${r.path}: ${state}.`);
34
- }
35
- // eslint-disable-next-line no-console
36
- console.log("");
37
- }
1
+ import {
2
+ FileService,
3
+ DocUpdater,
4
+ providersSection,
5
+ cliCommandsSection,
6
+ devWorkflowSection,
7
+ securityNoteSection,
8
+ CLI_COMMANDS,
9
+ } from "@gitpagedocs/tools";
10
+ import type { CommandContext } from "./run-command";
11
+
12
+ /**
13
+ * `gitpagedocs docs` — refresh the managed regions of the standard docs files
14
+ * with deterministic content. Idempotent and marker-bounded: manual content
15
+ * outside `<!-- gitpagedocs:start/end -->` is preserved; missing files are
16
+ * created. Covers README, CONTRIBUTING and SECURITY (master-spec docs set).
17
+ */
18
+ export async function runDocs(ctx: CommandContext): Promise<void> {
19
+ const updater = new DocUpdater(new FileService(ctx.cwd));
20
+
21
+ const updates = [
22
+ { path: "README.md", generated: `${providersSection()}\n\n${cliCommandsSection(CLI_COMMANDS)}` },
23
+ { path: "CONTRIBUTING.md", generated: `${devWorkflowSection()}\n\n${cliCommandsSection(CLI_COMMANDS)}` },
24
+ { path: "SECURITY.md", generated: securityNoteSection() },
25
+ ];
26
+
27
+ const results = await updater.updateManagedFiles(updates);
28
+ // eslint-disable-next-line no-console
29
+ console.log("");
30
+ for (const r of results) {
31
+ const state = r.changed ? (r.replaced ? "managed region updated" : "managed region added") : "already up to date";
32
+ // eslint-disable-next-line no-console
33
+ console.log(` ${r.path}: ${state}.`);
34
+ }
35
+ // eslint-disable-next-line no-console
36
+ console.log("");
37
+ }
@@ -1,20 +1,20 @@
1
- import type { CommandContext } from "./run-command";
2
-
3
- /**
4
- * `gitpagedocs mcp start` — entry point for the MCP server. The server package
5
- * (@gitpagedocs/mcp) is implemented in Phase 7; this command is wired to launch
6
- * it there. Until then it reports status honestly rather than failing silently.
7
- */
8
- export async function runMcp(ctx: CommandContext): Promise<void> {
9
- const sub = ctx.args[1] ?? "start";
10
- if (sub !== "start") {
11
- // eslint-disable-next-line no-console
12
- console.log(`\n Unknown mcp subcommand: ${sub}\n Usage: gitpagedocs mcp start\n`);
13
- return;
14
- }
15
- // stderr only: stdout is the MCP stdio channel and must stay protocol-clean.
16
- console.error("[gitpagedocs] Starting MCP server over stdio (Ctrl-C to stop)...");
17
- // Dynamic import keeps the MCP SDK out of the frontend bundle.
18
- const { startMcpServer } = await import("@gitpagedocs/mcp");
19
- await startMcpServer(ctx.cwd);
20
- }
1
+ import type { CommandContext } from "./run-command";
2
+
3
+ /**
4
+ * `gitpagedocs mcp start` — entry point for the MCP server. The server package
5
+ * (@gitpagedocs/mcp) is implemented in Phase 7; this command is wired to launch
6
+ * it there. Until then it reports status honestly rather than failing silently.
7
+ */
8
+ export async function runMcp(ctx: CommandContext): Promise<void> {
9
+ const sub = ctx.args[1] ?? "start";
10
+ if (sub !== "start") {
11
+ // eslint-disable-next-line no-console
12
+ console.log(`\n Unknown mcp subcommand: ${sub}\n Usage: gitpagedocs mcp start\n`);
13
+ return;
14
+ }
15
+ // stderr only: stdout is the MCP stdio channel and must stay protocol-clean.
16
+ console.error("[gitpagedocs] Starting MCP server over stdio (Ctrl-C to stop)...");
17
+ // Dynamic import keeps the MCP SDK out of the frontend bundle.
18
+ const { startMcpServer } = await import("@gitpagedocs/mcp");
19
+ await startMcpServer(ctx.cwd);
20
+ }
@@ -1,101 +1,101 @@
1
- import path from "node:path";
2
- import { spawnSync } from "node:child_process";
3
- import type { CommandContext } from "./run-command";
4
- import { askConfirm } from "../ui/clack";
5
- import { askOwnerRepo, interactivePromptsAvailable } from "../ui/prompts";
6
- // @ts-expect-error .mjs runtime module
7
- import { detectRepoFromGit, getCurrentGitBranch, tryConfigurePagesToGitHubActions } from "../../runtime/git-ops.mjs";
8
-
9
- /** Read `--name value` (or `--name=value`) from a raw arg list. */
10
- function readFlag(args: string[], name: string): string {
11
- const eq = args.find((a) => a.startsWith(`${name}=`));
12
- if (eq) return eq.slice(name.length + 1).trim();
13
- const i = args.indexOf(name);
14
- if (i >= 0 && args[i + 1] && !args[i + 1].startsWith("--")) return args[i + 1].trim();
15
- return "";
16
- }
17
-
18
- /**
19
- * `gitpagedocs pages actions` / `--pages-actions` — switch the repository's
20
- * GitHub Pages source to GitHub Actions. Detects owner/repo/branch from git,
21
- * validates the gh CLI, and confirms before changing anything (no silent
22
- * overwrite). Does NOT generate docs or push (that is `pages deploy`).
23
- */
24
- export async function runPagesActions(ctx: CommandContext): Promise<void> {
25
- let repo = detectRepoFromGit(ctx.cwd) as { owner: string; repo: string } | null;
26
- if (!repo) {
27
- if (!interactivePromptsAvailable()) {
28
- // eslint-disable-next-line no-console
29
- console.log("\n Could not detect a GitHub repo from the git 'origin' remote.\n Add a remote or use `--push --owner <o> --repo <r>`.\n");
30
- return;
31
- }
32
- repo = await askOwnerRepo(null);
33
- }
34
- const branch = getCurrentGitBranch(ctx.cwd) as string;
35
- // eslint-disable-next-line no-console
36
- console.log(`\n Detected ${repo.owner}/${repo.repo} (branch ${branch}).`);
37
- const ok = await askConfirm(`Switch GitHub Pages source to GitHub Actions for ${repo.owner}/${repo.repo}?`, false);
38
- if (!ok) {
39
- // eslint-disable-next-line no-console
40
- console.log(" Aborted. No changes made.\n");
41
- return;
42
- }
43
- tryConfigurePagesToGitHubActions(repo.owner, repo.repo, branch, ctx.cwd);
44
- }
45
-
46
- /**
47
- * `gitpagedocs pages deploy` — the full documented deploy flow: resolve
48
- * owner/repo (from --owner/--repo or the git remote), confirm, then run the
49
- * proven `--push` path (generate docs + workflow → commit → push → configure
50
- * Pages→Actions) and print the final site URL. Reuses the legacy push verbatim
51
- * (spawned), so `--push` behavior stays byte-identical.
52
- */
53
- export async function runPagesDeploy(ctx: CommandContext): Promise<void> {
54
- let owner = readFlag(ctx.args, "--owner");
55
- let repo = readFlag(ctx.args, "--repo");
56
- const docsPath = readFlag(ctx.args, "--path");
57
-
58
- if (!owner || !repo) {
59
- const detected = detectRepoFromGit(ctx.cwd) as { owner: string; repo: string } | null;
60
- if (detected) {
61
- owner = owner || detected.owner;
62
- repo = repo || detected.repo;
63
- }
64
- }
65
- if (!owner || !repo) {
66
- if (!interactivePromptsAvailable()) {
67
- // eslint-disable-next-line no-console
68
- console.log("\n Could not determine owner/repo. Pass `--owner <o> --repo <r>` or add a git 'origin' remote.\n");
69
- return;
70
- }
71
- const answered = await askOwnerRepo(null, { owner, repo });
72
- owner = answered.owner;
73
- repo = answered.repo;
74
- }
75
-
76
- // eslint-disable-next-line no-console
77
- console.log(`\n Deploy ${owner}/${repo} to GitHub Pages via Actions${docsPath ? ` (path: ${docsPath})` : ""}.`);
78
- const ok = await askConfirm(
79
- `Generate docs + workflow, commit, push, and switch Pages to Actions for ${owner}/${repo}?`,
80
- false,
81
- );
82
- if (!ok) {
83
- // eslint-disable-next-line no-console
84
- console.log(" Aborted. No changes made.\n");
85
- return;
86
- }
87
-
88
- // pkgRoot is the cli package root (cli/), where the bin lives as index.mjs.
89
- const bin = path.join(ctx.pkgRoot, "index.mjs");
90
- const pushArgs = ["--push", "--owner", owner, "--repo", repo, ...(docsPath ? ["--path", docsPath] : [])];
91
- const result = spawnSync(process.execPath, [bin, ...pushArgs], { stdio: "inherit", cwd: ctx.cwd, env: process.env });
92
-
93
- if (result.status === 0) {
94
- const seg = docsPath ? `/${docsPath.replace(/^\/+|\/+$/g, "")}` : "";
95
- // eslint-disable-next-line no-console
96
- console.log(`\n Deployed. Final URL: https://${owner}.github.io/${repo}${seg}/\n`);
97
- } else {
98
- // eslint-disable-next-line no-console
99
- console.log("\n Deploy did not complete (push step failed). See output above.\n");
100
- }
101
- }
1
+ import path from "node:path";
2
+ import { spawnSync } from "node:child_process";
3
+ import type { CommandContext } from "./run-command";
4
+ import { askConfirm } from "../ui/clack";
5
+ import { askOwnerRepo, interactivePromptsAvailable } from "../ui/prompts";
6
+ // @ts-expect-error .mjs runtime module
7
+ import { detectRepoFromGit, getCurrentGitBranch, tryConfigurePagesToGitHubActions } from "../../runtime/git-ops.mjs";
8
+
9
+ /** Read `--name value` (or `--name=value`) from a raw arg list. */
10
+ function readFlag(args: string[], name: string): string {
11
+ const eq = args.find((a) => a.startsWith(`${name}=`));
12
+ if (eq) return eq.slice(name.length + 1).trim();
13
+ const i = args.indexOf(name);
14
+ if (i >= 0 && args[i + 1] && !args[i + 1].startsWith("--")) return args[i + 1].trim();
15
+ return "";
16
+ }
17
+
18
+ /**
19
+ * `gitpagedocs pages actions` / `--pages-actions` — switch the repository's
20
+ * GitHub Pages source to GitHub Actions. Detects owner/repo/branch from git,
21
+ * validates the gh CLI, and confirms before changing anything (no silent
22
+ * overwrite). Does NOT generate docs or push (that is `pages deploy`).
23
+ */
24
+ export async function runPagesActions(ctx: CommandContext): Promise<void> {
25
+ let repo = detectRepoFromGit(ctx.cwd) as { owner: string; repo: string } | null;
26
+ if (!repo) {
27
+ if (!interactivePromptsAvailable()) {
28
+ // eslint-disable-next-line no-console
29
+ console.log("\n Could not detect a GitHub repo from the git 'origin' remote.\n Add a remote or use `--push --owner <o> --repo <r>`.\n");
30
+ return;
31
+ }
32
+ repo = await askOwnerRepo(null);
33
+ }
34
+ const branch = getCurrentGitBranch(ctx.cwd) as string;
35
+ // eslint-disable-next-line no-console
36
+ console.log(`\n Detected ${repo.owner}/${repo.repo} (branch ${branch}).`);
37
+ const ok = await askConfirm(`Switch GitHub Pages source to GitHub Actions for ${repo.owner}/${repo.repo}?`, false);
38
+ if (!ok) {
39
+ // eslint-disable-next-line no-console
40
+ console.log(" Aborted. No changes made.\n");
41
+ return;
42
+ }
43
+ tryConfigurePagesToGitHubActions(repo.owner, repo.repo, branch, ctx.cwd);
44
+ }
45
+
46
+ /**
47
+ * `gitpagedocs pages deploy` — the full documented deploy flow: resolve
48
+ * owner/repo (from --owner/--repo or the git remote), confirm, then run the
49
+ * proven `--push` path (generate docs + workflow → commit → push → configure
50
+ * Pages→Actions) and print the final site URL. Reuses the legacy push verbatim
51
+ * (spawned), so `--push` behavior stays byte-identical.
52
+ */
53
+ export async function runPagesDeploy(ctx: CommandContext): Promise<void> {
54
+ let owner = readFlag(ctx.args, "--owner");
55
+ let repo = readFlag(ctx.args, "--repo");
56
+ const docsPath = readFlag(ctx.args, "--path");
57
+
58
+ if (!owner || !repo) {
59
+ const detected = detectRepoFromGit(ctx.cwd) as { owner: string; repo: string } | null;
60
+ if (detected) {
61
+ owner = owner || detected.owner;
62
+ repo = repo || detected.repo;
63
+ }
64
+ }
65
+ if (!owner || !repo) {
66
+ if (!interactivePromptsAvailable()) {
67
+ // eslint-disable-next-line no-console
68
+ console.log("\n Could not determine owner/repo. Pass `--owner <o> --repo <r>` or add a git 'origin' remote.\n");
69
+ return;
70
+ }
71
+ const answered = await askOwnerRepo(null, { owner, repo });
72
+ owner = answered.owner;
73
+ repo = answered.repo;
74
+ }
75
+
76
+ // eslint-disable-next-line no-console
77
+ console.log(`\n Deploy ${owner}/${repo} to GitHub Pages via Actions${docsPath ? ` (path: ${docsPath})` : ""}.`);
78
+ const ok = await askConfirm(
79
+ `Generate docs + workflow, commit, push, and switch Pages to Actions for ${owner}/${repo}?`,
80
+ false,
81
+ );
82
+ if (!ok) {
83
+ // eslint-disable-next-line no-console
84
+ console.log(" Aborted. No changes made.\n");
85
+ return;
86
+ }
87
+
88
+ // pkgRoot is the cli package root (cli/), where the bin lives as index.mjs.
89
+ const bin = path.join(ctx.pkgRoot, "index.mjs");
90
+ const pushArgs = ["--push", "--owner", owner, "--repo", repo, ...(docsPath ? ["--path", docsPath] : [])];
91
+ const result = spawnSync(process.execPath, [bin, ...pushArgs], { stdio: "inherit", cwd: ctx.cwd, env: process.env });
92
+
93
+ if (result.status === 0) {
94
+ const seg = docsPath ? `/${docsPath.replace(/^\/+|\/+$/g, "")}` : "";
95
+ // eslint-disable-next-line no-console
96
+ console.log(`\n Deployed. Final URL: https://${owner}.github.io/${repo}${seg}/\n`);
97
+ } else {
98
+ // eslint-disable-next-line no-console
99
+ console.log("\n Deploy did not complete (push step failed). See output above.\n");
100
+ }
101
+ }