@inditextech/docouture-cli 0.1.0-SNAPSHOT.40.1

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 (94) hide show
  1. package/build/bin.js +321 -0
  2. package/build/commands/build.js +22 -0
  3. package/build/commands/completion.js +69 -0
  4. package/build/commands/dev.js +67 -0
  5. package/build/commands/doctor.js +156 -0
  6. package/build/commands/eject.js +71 -0
  7. package/build/commands/new.js +512 -0
  8. package/build/commands/publish.js +111 -0
  9. package/build/commands/teardown.js +66 -0
  10. package/build/commands/upgrade.js +156 -0
  11. package/build/commands/version.js +60 -0
  12. package/build/lib/agents-md.js +67 -0
  13. package/build/lib/antora-log.js +36 -0
  14. package/build/lib/antora-yml.js +47 -0
  15. package/build/lib/args.js +26 -0
  16. package/build/lib/cli-context.js +17 -0
  17. package/build/lib/cli-info.js +20 -0
  18. package/build/lib/config-resolver.js +23 -0
  19. package/build/lib/copy-template.js +162 -0
  20. package/build/lib/debug-log.js +21 -0
  21. package/build/lib/detect-package-manager.js +79 -0
  22. package/build/lib/dev-server.js +337 -0
  23. package/build/lib/doctor-checks.js +240 -0
  24. package/build/lib/global-flags.js +31 -0
  25. package/build/lib/kroki-compose.js +54 -0
  26. package/build/lib/playbook-yml.js +90 -0
  27. package/build/lib/repo-root.js +21 -0
  28. package/build/lib/run-script.js +50 -0
  29. package/build/lib/theme.js +51 -0
  30. package/build/templates/agent-support/.claude/skills/docs-internals/SKILL.md +53 -0
  31. package/build/templates/agent-support/.claude/skills/docs-internals/reference/antora-extensions.md +54 -0
  32. package/build/templates/agent-support/.claude/skills/docs-internals/reference/naming.md +41 -0
  33. package/build/templates/agent-support/.claude/skills/docs-internals/reference/page-patterns.md +238 -0
  34. package/build/templates/agent-support/.claude/skills/docs-versioning.versioned/SKILL.md +37 -0
  35. package/build/templates/agent-support/.claude/skills/docs-versioning.versioned/reference/releasing.md +106 -0
  36. package/build/templates/agent-support/.claude/skills/documenting-your-repo/SKILL.md +55 -0
  37. package/build/templates/agent-support/.claude/skills/documenting-your-repo/reference/content-sourcing.md +55 -0
  38. package/build/templates/agent-support/.claude/skills/documenting-your-repo/reference/maintenance-loop.md +68 -0
  39. package/build/templates/agent-support/.claude/skills/documenting-your-repo/reference/structure-planning.md +102 -0
  40. package/build/templates/agent-support/.claude/skills/writing-docs-pages/SKILL.md +112 -0
  41. package/build/templates/agent-support/.claude/skills/writing-docs-pages/reference/docouture-blocks.md +170 -0
  42. package/build/templates/agent-support/.claude/skills/writing-docs-pages/reference/language-basics.md +402 -0
  43. package/build/templates/agent-support/.opencode/skills/docs-internals/SKILL.md +53 -0
  44. package/build/templates/agent-support/.opencode/skills/docs-internals/reference/antora-extensions.md +54 -0
  45. package/build/templates/agent-support/.opencode/skills/docs-internals/reference/naming.md +41 -0
  46. package/build/templates/agent-support/.opencode/skills/docs-internals/reference/page-patterns.md +238 -0
  47. package/build/templates/agent-support/.opencode/skills/docs-versioning.versioned/SKILL.md +37 -0
  48. package/build/templates/agent-support/.opencode/skills/docs-versioning.versioned/reference/releasing.md +106 -0
  49. package/build/templates/agent-support/.opencode/skills/documenting-your-repo/SKILL.md +55 -0
  50. package/build/templates/agent-support/.opencode/skills/documenting-your-repo/reference/content-sourcing.md +55 -0
  51. package/build/templates/agent-support/.opencode/skills/documenting-your-repo/reference/maintenance-loop.md +68 -0
  52. package/build/templates/agent-support/.opencode/skills/documenting-your-repo/reference/structure-planning.md +102 -0
  53. package/build/templates/agent-support/.opencode/skills/writing-docs-pages/SKILL.md +112 -0
  54. package/build/templates/agent-support/.opencode/skills/writing-docs-pages/reference/docouture-blocks.md +170 -0
  55. package/build/templates/agent-support/.opencode/skills/writing-docs-pages/reference/language-basics.md +402 -0
  56. package/build/templates/agent-support/AGENTS.md +72 -0
  57. package/build/templates/starter/antora-playbook.local.yml +99 -0
  58. package/build/templates/starter/antora-playbook.versioned.yml +167 -0
  59. package/build/templates/starter/antora-playbook.yml +189 -0
  60. package/build/templates/starter/gitignore +3 -0
  61. package/build/templates/starter/package.json +37 -0
  62. package/build/templates/starter/scripts/check-links.mjs +178 -0
  63. package/build/templates/starter/src/antora.yml +85 -0
  64. package/build/templates/starter/src/modules/ROOT/images/card-placeholder.png +0 -0
  65. package/build/templates/starter/src/modules/ROOT/images/feature-placeholder-dark.png +0 -0
  66. package/build/templates/starter/src/modules/ROOT/images/feature-placeholder.png +0 -0
  67. package/build/templates/starter/src/modules/ROOT/images/hero-placeholder.png +0 -0
  68. package/build/templates/starter/src/modules/ROOT/pages/index.adoc +124 -0
  69. package/build/templates/starter/src/modules/main/nav.adoc +19 -0
  70. package/build/templates/starter/src/modules/main/pages/app.adoc +5 -0
  71. package/build/templates/starter/src/modules/main/pages/architecture.adoc +6 -0
  72. package/build/templates/starter/src/modules/main/pages/changelog/index.adoc +9 -0
  73. package/build/templates/starter/src/modules/main/pages/components.adoc +701 -0
  74. package/build/templates/starter/src/modules/main/pages/contributing.adoc +6 -0
  75. package/build/templates/starter/src/modules/main/pages/getting-started.adoc +169 -0
  76. package/build/templates/starter/src/modules/main/pages/glossary.adoc +8 -0
  77. package/build/templates/starter/src/modules/main/pages/index.adoc +9 -0
  78. package/build/templates/starter/src/modules/main/pages/prerequisites.adoc +55 -0
  79. package/build/templates/starter/src/modules/main/pages/quickstart.adoc +21 -0
  80. package/build/templates/starter/src/modules/main/pages/release-notes/index.adoc +9 -0
  81. package/build/templates/starter/src/modules/main/pages/requirements.adoc +8 -0
  82. package/build/templates/starter/src/modules/main/pages/roadmap.adoc +4 -0
  83. package/build/templates/starter/src/modules/main/pages/structure.adoc +5 -0
  84. package/build/templates/starter/src/release-version.versioned +1 -0
  85. package/build/templates/starter/supplemental-ui/favicon.ico +0 -0
  86. package/build/templates/starter/supplemental-ui/product-logo-dark.png +0 -0
  87. package/build/templates/starter/supplemental-ui/product-logo.png +0 -0
  88. package/build/templates/workflows/docouture-kroki-cache-warm.yml +101 -0
  89. package/build/templates/workflows/docouture-pr-verify.yml +120 -0
  90. package/build/templates/workflows/docouture-publish-prerelease.yml +122 -0
  91. package/build/templates/workflows/docouture-publish.yml +138 -0
  92. package/build/templates/workflows/docouture-release-preview.yml +198 -0
  93. package/build/templates/workflows/docouture-release.yml +414 -0
  94. package/package.json +38 -0
package/build/bin.js ADDED
@@ -0,0 +1,321 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+ import { runNew } from './commands/new.js';
4
+ import { runVersion } from './commands/version.js';
5
+ import { runDev } from './commands/dev.js';
6
+ import { runBuild } from './commands/build.js';
7
+ import { runDoctor } from './commands/doctor.js';
8
+ import { runPublish } from './commands/publish.js';
9
+ import { runUpgrade } from './commands/upgrade.js';
10
+ import { runEject } from './commands/eject.js';
11
+ import { runTeardown } from './commands/teardown.js';
12
+ import { runCompletion } from './commands/completion.js';
13
+ import { readCliInfo } from './lib/cli-info.js';
14
+ import { setContext } from './lib/cli-context.js';
15
+ import { theme } from './lib/theme.js';
16
+ import { extractGlobalFlags } from './lib/global-flags.js';
17
+ const COMMAND_ORDER = [
18
+ 'new',
19
+ 'version',
20
+ 'dev',
21
+ 'build',
22
+ 'publish',
23
+ 'doctor',
24
+ 'upgrade',
25
+ 'eject',
26
+ 'teardown',
27
+ 'completion',
28
+ ];
29
+ const COMMAND_INFO = {
30
+ new: {
31
+ usageLine: 'new <name>',
32
+ summary: 'Scaffold a new documentation site',
33
+ help: `Usage:
34
+ docouture new <name> [--dir <path>] [--title <title>] [--mode standalone|versioned] [--pm npm|pnpm] [--yes]
35
+
36
+ Scaffold an Antora documentation site into docs/ (and its workflows into
37
+ .github/workflows/), plus AGENTS.md and agent skills (.opencode/skills/,
38
+ .claude/skills/) into the root of an existing git repository. --dir/cwd
39
+ can be anywhere inside that repository — the actual top-level is found
40
+ automatically. If any workflows, skills or a docouture-managed AGENTS.md
41
+ section already exist, prompts to overwrite them (refuses outright when
42
+ not running interactively). Prompts interactively for anything not given
43
+ as a flag when run in a terminal (pass --yes to always use defaults, and
44
+ to never prompt to overwrite, instead).
45
+
46
+ Options:
47
+ --dir <path> Repository root to scaffold into (default: cwd, or its enclosing repo)
48
+ --title <title> Site title (default: title-cased from <name>)
49
+ --mode <mode> 'standalone' (default) or 'versioned'
50
+ --pm <pm> 'npm' or 'pnpm' (default: auto-detected from a lockfile/packageManager
51
+ field, or how docouture itself was invoked)
52
+ --yes Skip the interactive wizard, use defaults for anything unset
53
+ `,
54
+ },
55
+ version: {
56
+ usageLine: 'version <value>',
57
+ summary: 'Set the version recorded in docs/antora.yml',
58
+ help: `Usage:
59
+ docouture version <value> [--dir <path>] [--file <path>] [--prerelease | --stable]
60
+
61
+ Set the version recorded in docs/antora.yml.
62
+
63
+ Options:
64
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
65
+ --file <path> antora.yml path directly, overrides --dir
66
+ --prerelease Mark this version as a prerelease
67
+ --stable Mark this version as stable (mutually exclusive with --prerelease)
68
+ `,
69
+ },
70
+ dev: {
71
+ usageLine: 'dev',
72
+ summary: 'Build and serve the site with live reload',
73
+ help: `Usage:
74
+ docouture dev [--port <port>] [--dir <path>]
75
+
76
+ Build the site and serve it with live reload, rebuilding on every
77
+ change to docs/ or antora-playbook.yml. --dir is the repository root
78
+ (the parent of docs/), same as new/version — not the site directory.
79
+
80
+ Options:
81
+ --port <port> Port to listen on (default: 5000)
82
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
83
+ `,
84
+ },
85
+ build: {
86
+ usageLine: 'build',
87
+ summary: 'Build the site once',
88
+ help: `Usage:
89
+ docouture build [--dir <path>]
90
+
91
+ Build the site once: a thin wrapper around the site's own 'npm run
92
+ build' (antora --fetch antora-playbook.yml).
93
+
94
+ Options:
95
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
96
+ `,
97
+ },
98
+ publish: {
99
+ usageLine: 'publish <target>',
100
+ summary: 'Publish the already-built site',
101
+ help: `Usage:
102
+ docouture publish <target> [--dir <path>] [--<option> <value> ...]
103
+
104
+ Publish the already-built site (output.dir in antora-playbook.yml,
105
+ default build/site — run 'docouture build' first) using the
106
+ '@inditextech/docouture-publish-<target>' driver, e.g. 'gh-pages'. That
107
+ package must be a devDependency of the site itself. Options come
108
+ from docs/package.json's own "docouture".publish.<target> object,
109
+ overridden by any --flags given here.
110
+
111
+ Options:
112
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
113
+ --<option> <value> Forwarded to the publish driver as one of its own options
114
+ --user-name/--user-email Combined into a nested {user:{name,email}} option
115
+
116
+ Example:
117
+ docouture publish gh-pages --branch gh-pages
118
+ `,
119
+ },
120
+ doctor: {
121
+ usageLine: 'doctor',
122
+ summary: 'Check environment and site health',
123
+ help: `Usage:
124
+ docouture doctor [--dir <path>] [--json]
125
+
126
+ Check that the environment and site configuration are healthy: Node
127
+ version, the four names that must agree (component name, start page,
128
+ content path, package name), git history, that antora is installed,
129
+ and (advisory only) whether AGENTS.md and the scaffolded skills are
130
+ still present.
131
+
132
+ Options:
133
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
134
+ --json Print a machine-readable report to stdout instead
135
+ `,
136
+ },
137
+ upgrade: {
138
+ usageLine: 'upgrade',
139
+ summary: 'Re-sync workflows and agent support files',
140
+ help: `Usage:
141
+ docouture upgrade [--dir <path>] [--title <title>] [--dry-run]
142
+
143
+ Re-sync an already-scaffolded repository's .github/workflows/ and
144
+ agent support files (AGENTS.md, .opencode/skills/, .claude/skills/)
145
+ from the CLI's current templates — --dir/cwd can be anywhere inside
146
+ that repository, the actual top-level is found automatically.
147
+ Workflows and skills are fully overwritten; AGENTS.md is merged
148
+ instead — only docouture' own managed section is replaced, anything a
149
+ human added around it survives. Does not touch docs/. --dry-run lists
150
+ what would be written without changing anything.
151
+
152
+ Options:
153
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
154
+ --title <title> Override the title read back from docs/antora.yml
155
+ --dry-run List what would be written without changing anything
156
+ `,
157
+ },
158
+ eject: {
159
+ usageLine: 'eject <target>',
160
+ summary: 'Copy a bundled default file out for customization',
161
+ help: `Usage:
162
+ docouture eject <target> [--dir <path>]
163
+
164
+ Copy a bundled default file out into docs/ for local customization.
165
+ 'kroki': docs/kroki-compose.yml, the docker compose definition
166
+ @inditextech/docouture-antora-extensions' kroki-prewarm.js starts
167
+ automatically when a build needs Kroki (kroki-enabled: true) and finds
168
+ nothing already running — auto-detected and preferred over the
169
+ bundled default once it exists. Refuses to overwrite an existing file.
170
+
171
+ Options:
172
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
173
+ `,
174
+ },
175
+ teardown: {
176
+ usageLine: 'teardown <target>',
177
+ summary: 'Stop a service docouture started for you',
178
+ help: `Usage:
179
+ docouture teardown <target> [--dir <path>]
180
+
181
+ Stop a service docouture started for you. 'kroki': runs 'docker compose
182
+ down' against whichever kroki-compose.yml is actually in effect (an
183
+ ejected docs/kroki-compose.yml if you have one, else the bundled
184
+ default) — the manual counterpart to kroki-prewarm.js's own auto-start,
185
+ which never stops it itself.
186
+
187
+ Options:
188
+ --dir <path> Repository root (default: cwd, or its enclosing repo)
189
+ `,
190
+ },
191
+ completion: {
192
+ usageLine: 'completion <shell>',
193
+ summary: 'Print a shell completion script (bash|zsh)',
194
+ help: `Usage:
195
+ docouture completion <bash|zsh>
196
+
197
+ Print a shell completion script for docouture to stdout.
198
+
199
+ Examples:
200
+ eval "$(docouture completion bash)"
201
+ docouture completion zsh > "\${fpath[1]}/_docouture"
202
+ `,
203
+ },
204
+ };
205
+ // Top-level equivalent of each COMMAND_INFO entry's `summary` — printed as
206
+ // the title of the bare/--help screen, same 'docouture — <summary>' shape as
207
+ // 'docouture <command> --help' uses for a single command.
208
+ const CLI_SUMMARY = 'Scaffold, build, and publish Antora documentation sites';
209
+ // Left column width of the command table below, including the 2-space
210
+ // indent — wide enough for the longest usageLine ('completion <shell>').
211
+ const COMMAND_COLUMN_WIDTH = 22;
212
+ const USAGE = `Usage: docouture <command> [options]
213
+
214
+ Commands:
215
+ ${COMMAND_ORDER.map((cmd) => {
216
+ const info = COMMAND_INFO[cmd];
217
+ return ` ${info.usageLine}`.padEnd(COMMAND_COLUMN_WIDTH) + info.summary;
218
+ }).join('\n')}
219
+
220
+ Global options:
221
+ -h, --help Show help (pass after a command for command-specific help)
222
+ -v, --version Print the installed @inditextech/docouture-cli version and exit
223
+ --json Machine-readable output where supported (currently: doctor)
224
+ --verbose Print extra diagnostic detail to stderr (same as DEBUG=docouture)
225
+ --no-color Disable coloured output regardless of TTY detection
226
+
227
+ Run 'docouture <command> --help' for command-specific usage and options.
228
+ `;
229
+ const RUNNERS = {
230
+ new: runNew,
231
+ version: runVersion,
232
+ dev: runDev,
233
+ build: runBuild,
234
+ publish: runPublish,
235
+ doctor: runDoctor,
236
+ upgrade: runUpgrade,
237
+ eject: runEject,
238
+ teardown: runTeardown,
239
+ completion: async (argv) => runCompletion(argv),
240
+ };
241
+ // completion's whole output must be shell-consumable on stdout (piped to a
242
+ // file, or `eval`'d directly on every shell startup if a user wires it into
243
+ // their rc file) — the banner is harmless there too, since it only ever
244
+ // goes to stderr, but printing it on every single new shell would still be
245
+ // needless noise for something meant to be sourced silently.
246
+ const QUIET_COMMANDS = new Set(['completion']);
247
+ // build/bin.js -> package root, 1 level up — see readCliInfo's own comment.
248
+ async function banner() {
249
+ const { name, version } = await readCliInfo(import.meta.url, 1);
250
+ return `${theme.bold(theme.info(name))} ${theme.dim(`v${version}`)}`;
251
+ }
252
+ // Recognises the three global flags anywhere in argv (before or after the
253
+ // command name — `docouture --verbose dev` and `docouture dev --verbose` both
254
+ // work), strips them out, and returns what's left for command dispatch —
255
+ // see lib/global-flags.ts.
256
+ async function main() {
257
+ const { json, verbose, noColor, rest: argv } = extractGlobalFlags(process.argv.slice(2));
258
+ setContext({ json, verbose, noColor });
259
+ const [command, ...rest] = argv;
260
+ if (command === '--version' || command === '-v') {
261
+ console.log(await banner());
262
+ return 0;
263
+ }
264
+ // Bare invocation prints help and succeeds — mirrors git/npm's own
265
+ // convention of treating "show me what you can do" as a legitimate,
266
+ // successful outcome rather than an error, unlike a genuinely unknown
267
+ // command below.
268
+ if (command === undefined || command === '--help' || command === '-h' || command === 'help') {
269
+ console.log(await banner());
270
+ console.log('');
271
+ console.log(theme.bold(`docouture — ${CLI_SUMMARY}`));
272
+ console.log('');
273
+ console.log(USAGE);
274
+ return 0;
275
+ }
276
+ if (command in COMMAND_INFO && (rest[0] === '--help' || rest[0] === '-h')) {
277
+ const info = COMMAND_INFO[command];
278
+ console.log(await banner());
279
+ console.log('');
280
+ console.log(theme.bold(`docouture ${command} — ${info.summary}`));
281
+ console.log('');
282
+ console.log(info.help);
283
+ return 0;
284
+ }
285
+ if (!(command in RUNNERS)) {
286
+ console.error(`unknown command: '${command}'\n`);
287
+ console.error(await banner());
288
+ console.error('');
289
+ console.error(theme.bold(`docouture — ${CLI_SUMMARY}`));
290
+ console.error('');
291
+ console.error(USAGE);
292
+ return 1;
293
+ }
294
+ // Printed once per invocation, to stderr — so it never lands in piped or
295
+ // parsed stdout — right before the command actually runs, rather than
296
+ // only on --version/--help/error paths as before. Suppressed under
297
+ // --json (stdout is promised clean there; a stray stderr banner is still
298
+ // needless noise for a script capturing combined output) and for
299
+ // completion (see QUIET_COMMANDS' own comment). The title line repeats
300
+ // the same '<command> — <summary>' shown on --help, so a plain run gives
301
+ // just as much "what is this" context as asking for help would — followed
302
+ // by a blank line so the command's own output never runs straight on
303
+ // from the banner/title.
304
+ if (!json && !QUIET_COMMANDS.has(command)) {
305
+ const info = COMMAND_INFO[command];
306
+ console.error(await banner());
307
+ console.error('');
308
+ console.error(theme.bold(`docouture ${command} — ${info.summary}`));
309
+ console.error('');
310
+ }
311
+ return RUNNERS[command](rest);
312
+ }
313
+ main()
314
+ .then((code) => {
315
+ process.exitCode = code;
316
+ })
317
+ .catch((err) => {
318
+ console.error(err instanceof Error ? err.stack : String(err));
319
+ process.exitCode = 1;
320
+ });
321
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1,22 @@
1
+ 'use strict';
2
+ import { join, resolve } from 'node:path';
3
+ import { parseArgs } from '../lib/args.js';
4
+ import { ANTORA_LOG_LEVEL_ARGS } from '../lib/antora-log.js';
5
+ import { exists } from '../lib/copy-template.js';
6
+ import { findRepoRoot } from '../lib/repo-root.js';
7
+ import { runNpmScript } from '../lib/run-script.js';
8
+ export async function runBuild(argv) {
9
+ const { flags } = parseArgs(argv);
10
+ // --dir (or cwd) can be anywhere inside the repository — findRepoRoot
11
+ // walks up to the actual repository root, same as `new`/`version`/`doctor`.
12
+ const startDir = typeof flags.dir === 'string' ? resolve(flags.dir) : resolve(process.cwd());
13
+ const target = await findRepoRoot(startDir);
14
+ const siteRoot = join(target, 'docs');
15
+ if (!(await exists(join(siteRoot, 'package.json')))) {
16
+ console.error(`no package.json found at '${siteRoot}'`);
17
+ console.error('pass --dir <path> to a component root (the parent of docs/), or run docouture new first');
18
+ return 1;
19
+ }
20
+ return runNpmScript('build', { cwd: siteRoot, args: [...ANTORA_LOG_LEVEL_ARGS] });
21
+ }
22
+ //# sourceMappingURL=build.js.map
@@ -0,0 +1,69 @@
1
+ 'use strict';
2
+ // `docouture completion <bash|zsh>` — prints a completion script to stdout (so
3
+ // `docouture completion bash > file` and `eval "$(docouture completion bash)"` both
4
+ // work); everything else this command has to say (usage errors) goes to
5
+ // stderr, same discipline as every other command. The candidate list is
6
+ // kept here as a literal array rather than derived from bin.ts's dispatch
7
+ // table, since introducing a shared "registry" module for nine commands
8
+ // that essentially never change is more machinery than the problem needs —
9
+ // see COMMANDS' own comment for what keeps it honest.
10
+ // Kept in sync with bin.ts's RUNNERS keys by test (completion.spec.ts) —
11
+ // not by import, since bin.ts is the entrypoint and importing it back here
12
+ // would run its top-level `main()` invocation.
13
+ export const COMMANDS = [
14
+ 'new',
15
+ 'version',
16
+ 'dev',
17
+ 'build',
18
+ 'publish',
19
+ 'doctor',
20
+ 'upgrade',
21
+ 'eject',
22
+ 'teardown',
23
+ 'completion',
24
+ ];
25
+ function bashScript() {
26
+ const words = COMMANDS.join(' ');
27
+ return `# docouture bash completion
28
+ #
29
+ # Install for the current session:
30
+ # eval "$(docouture completion bash)"
31
+ #
32
+ # Install permanently, e.g. on macOS with Homebrew's bash-completion@2:
33
+ # docouture completion bash > "$(brew --prefix)/etc/bash_completion.d/docouture"
34
+ _docouture_completions() {
35
+ local cur=\${COMP_WORDS[COMP_CWORD]}
36
+ COMPREPLY=($(compgen -W "${words}" -- "$cur"))
37
+ }
38
+ complete -F _docouture_completions docouture
39
+ `;
40
+ }
41
+ function zshScript() {
42
+ const words = COMMANDS.map((c) => `'${c}'`).join(' ');
43
+ return `#compdef docouture
44
+ # docouture zsh completion
45
+ #
46
+ # Install by placing this on your $fpath, e.g.:
47
+ # docouture completion zsh > "\${fpath[1]}/_docouture"
48
+ _docouture() {
49
+ local -a commands
50
+ commands=(${words})
51
+ _describe 'docouture command' commands
52
+ }
53
+ _docouture
54
+ `;
55
+ }
56
+ export function runCompletion(argv) {
57
+ const shell = argv[0];
58
+ if (shell === 'bash') {
59
+ process.stdout.write(bashScript());
60
+ return 0;
61
+ }
62
+ if (shell === 'zsh') {
63
+ process.stdout.write(zshScript());
64
+ return 0;
65
+ }
66
+ console.error('usage: docouture completion <bash|zsh>');
67
+ return 1;
68
+ }
69
+ //# sourceMappingURL=completion.js.map
@@ -0,0 +1,67 @@
1
+ 'use strict';
2
+ import { join, resolve } from 'node:path';
3
+ import ora from 'ora';
4
+ import { parseArgs } from '../lib/args.js';
5
+ import { exists } from '../lib/copy-template.js';
6
+ import { findRepoRoot } from '../lib/repo-root.js';
7
+ import { startDevServer } from '../lib/dev-server.js';
8
+ export async function runDev(argv) {
9
+ const { flags } = parseArgs(argv);
10
+ // --dir (or cwd) can be anywhere inside the repository — findRepoRoot
11
+ // walks up to the actual repository root, same as `new`/`version`/`doctor`.
12
+ const startDir = typeof flags.dir === 'string' ? resolve(flags.dir) : resolve(process.cwd());
13
+ const target = await findRepoRoot(startDir);
14
+ const siteRoot = join(target, 'docs');
15
+ if (!(await exists(join(siteRoot, 'antora-playbook.local.yml')))) {
16
+ console.error(`no antora-playbook.local.yml found at '${siteRoot}'`);
17
+ console.error('pass --dir <path> to a component root (the parent of docs/), or run docouture new first');
18
+ return 1;
19
+ }
20
+ let port;
21
+ if (typeof flags.port === 'string') {
22
+ port = Number(flags.port);
23
+ if (!Number.isInteger(port) || port <= 0) {
24
+ console.error(`invalid --port: '${flags.port}'`);
25
+ return 1;
26
+ }
27
+ }
28
+ // Spinner covers only the initial build+listen wait, where the previous
29
+ // behaviour was otherwise silent for however long the first Antora build
30
+ // takes — ora auto-detects a non-TTY stderr (CI, piped output) and
31
+ // degrades to plain text on its own, so this stays quiet under
32
+ // automation without a separate flag. Once the server is up, log/logError
33
+ // below revert to plain per-rebuild lines exactly as before.
34
+ const spinner = ora({ text: 'Starting dev server…', stream: process.stderr }).start();
35
+ let ready = false;
36
+ const log = (msg) => {
37
+ if (ready)
38
+ console.error(`dev ${msg}`);
39
+ };
40
+ const logError = (msg) => {
41
+ if (ready)
42
+ console.error(`dev ${msg}`);
43
+ };
44
+ try {
45
+ const server = await startDevServer({ siteRoot, port, log, logError });
46
+ ready = true;
47
+ spinner.succeed(`Serving ${server.url}`);
48
+ await new Promise((resolvePromise) => {
49
+ const shutdown = () => {
50
+ void server.close().then(resolvePromise);
51
+ };
52
+ process.once('SIGINT', shutdown);
53
+ process.once('SIGTERM', shutdown);
54
+ });
55
+ return 0;
56
+ }
57
+ catch (err) {
58
+ if (err?.code === 'EADDRINUSE') {
59
+ spinner.fail(`port ${port ?? 5000} is already in use`);
60
+ console.error(' stop whatever is listening on it, or pass --port <port>');
61
+ return 1;
62
+ }
63
+ spinner.fail(err instanceof Error ? err.message : String(err));
64
+ return 1;
65
+ }
66
+ }
67
+ //# sourceMappingURL=dev.js.map
@@ -0,0 +1,156 @@
1
+ 'use strict';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { dirname, join, relative, resolve, sep } from 'node:path';
4
+ import { parseArgs } from '../lib/args.js';
5
+ import { exists } from '../lib/copy-template.js';
6
+ import { findRepoRoot } from '../lib/repo-root.js';
7
+ import { getContext } from '../lib/cli-context.js';
8
+ import { theme } from '../lib/theme.js';
9
+ import { readSourceUrl, readStartPageComponent, readStartPath } from '../lib/playbook-yml.js';
10
+ import { checkAgentFilesPresent, checkAntoraAvailable, checkGitHasCommit, checkNamesAgree, checkNodeVersion, checkReleaseLabelExists, } from '../lib/doctor-checks.js';
11
+ async function readJson(file) {
12
+ try {
13
+ return JSON.parse(await readFile(file, 'utf8'));
14
+ }
15
+ catch {
16
+ return null;
17
+ }
18
+ }
19
+ function readAntoraYmlName(content) {
20
+ const match = /^name:\s*(.+?)\s*$/m.exec(content);
21
+ return match?.[1] ?? null;
22
+ }
23
+ // Every check is recorded here as it runs, in section order, regardless of
24
+ // whether the human-readable report or --json is what actually gets
25
+ // printed — this is the one source of truth both output modes read from,
26
+ // so they can never drift from each other on which checks ran or what they
27
+ // found.
28
+ function record(report, section, result, severity) {
29
+ report.push({ ...result, section, severity: result.ok ? 'ok' : severity });
30
+ if (severity === 'fail')
31
+ return result.ok ? 0 : 1;
32
+ return 0;
33
+ }
34
+ function printResult(result) {
35
+ const ok = theme.success(' ok ');
36
+ const fail = theme.error('FAIL');
37
+ console.log(` ${result.ok ? ok : fail} ${result.label} — ${result.message}`);
38
+ if (!result.ok && result.detail) {
39
+ console.log(` ${result.detail}`);
40
+ }
41
+ }
42
+ // Same rendering as printResult, but never contributes to the overall exit
43
+ // code — used only for advisory checks (agent files, release label): 'warn'
44
+ // instead of 'FAIL' so a missing file reads as advisory, not as the same
45
+ // severity as a broken build.
46
+ function printAdvisory(result) {
47
+ const ok = theme.success(' ok ');
48
+ const warn = theme.warn('warn');
49
+ console.log(` ${result.ok ? ok : warn} ${result.label} — ${result.message}`);
50
+ if (!result.ok && result.detail) {
51
+ console.log(` ${result.detail}`);
52
+ }
53
+ }
54
+ export async function runDoctor(argv) {
55
+ const { flags } = parseArgs(argv);
56
+ const json = getContext().json;
57
+ const startDir = typeof flags.dir === 'string' ? resolve(flags.dir) : resolve(process.cwd());
58
+ // --dir (or cwd) can be anywhere inside the repository — its root, inside
59
+ // docs/, wherever — findRepoRoot walks up to find the actual repository
60
+ // root the same way `git` itself would, so doctor always looks at
61
+ // <repoRoot>/docs regardless of where it was invoked from.
62
+ const target = await findRepoRoot(startDir);
63
+ const siteRoot = join(target, 'docs');
64
+ if (!(await exists(siteRoot))) {
65
+ console.error(`no site found at '${siteRoot}'`);
66
+ console.error('pass --dir <path> to a component root (the parent of docs/), or run docouture new first');
67
+ return 1;
68
+ }
69
+ let status = 0;
70
+ const report = [];
71
+ const log = (line) => {
72
+ if (!json)
73
+ console.log(line);
74
+ };
75
+ log('toolchain');
76
+ const pkg = await readJson(join(siteRoot, 'package.json'));
77
+ const nodeResult = checkNodeVersion(pkg?.engines?.node, process.version);
78
+ status |= record(report, 'toolchain', nodeResult, 'fail');
79
+ if (!json)
80
+ printResult(nodeResult);
81
+ log('names');
82
+ const playbookFile = join(siteRoot, 'antora-playbook.yml');
83
+ const antoraYmlFile = join(siteRoot, 'src', 'antora.yml');
84
+ const playbookContent = (await exists(playbookFile)) ? await readFile(playbookFile, 'utf8') : null;
85
+ const antoraYmlContent = (await exists(antoraYmlFile)) ? await readFile(antoraYmlFile, 'utf8') : null;
86
+ if (!playbookContent) {
87
+ const result = { ok: false, label: 'antora-playbook.yml', message: `not found at '${playbookFile}'` };
88
+ status |= record(report, 'names', result, 'fail');
89
+ if (!json)
90
+ printResult(result);
91
+ }
92
+ if (!antoraYmlContent) {
93
+ const result = { ok: false, label: 'src/antora.yml', message: `not found at '${antoraYmlFile}'` };
94
+ status |= record(report, 'names', result, 'fail');
95
+ if (!json)
96
+ printResult(result);
97
+ }
98
+ if (playbookContent && antoraYmlContent) {
99
+ const sourceUrl = readSourceUrl(playbookContent);
100
+ if (sourceUrl && sourceUrl !== '.') {
101
+ // The repository-root-relative form of `src/antora.yml`'s real
102
+ // location — see lib/playbook-yml.ts's own comment on why `url: .`
103
+ // only works when the playbook itself sits at the repository root.
104
+ const descriptorPath = relative(target, dirname(antoraYmlFile)).split(sep).join('/');
105
+ const results = checkNamesAgree({
106
+ antoraYmlName: readAntoraYmlName(antoraYmlContent),
107
+ startPageComponent: readStartPageComponent(playbookContent),
108
+ startPath: readStartPath(playbookContent),
109
+ descriptorPath,
110
+ packageName: pkg?.name ?? null,
111
+ });
112
+ for (const result of results) {
113
+ status |= record(report, 'names', result, 'fail');
114
+ if (!json)
115
+ printResult(result);
116
+ }
117
+ }
118
+ else {
119
+ const result = {
120
+ ok: false,
121
+ label: 'content source url',
122
+ message: `content.sources[0].url is '.' but the playbook does not sit at the repository root`,
123
+ detail: "url: '.' only works when antora-playbook.yml sits at the repository root — use 'url: ..' (or however many levels reach it) otherwise",
124
+ };
125
+ status |= record(report, 'names', result, 'fail');
126
+ if (!json)
127
+ printResult(result);
128
+ }
129
+ }
130
+ log('content');
131
+ const gitResult = await checkGitHasCommit(target);
132
+ status |= record(report, 'content', gitResult, 'fail');
133
+ if (!json)
134
+ printResult(gitResult);
135
+ log('dependencies');
136
+ const antoraResult = checkAntoraAvailable(siteRoot);
137
+ status |= record(report, 'dependencies', antoraResult, 'fail');
138
+ if (!json)
139
+ printResult(antoraResult);
140
+ log('agent files');
141
+ for (const result of checkAgentFilesPresent(target)) {
142
+ record(report, 'agent files', result, 'warn');
143
+ if (!json)
144
+ printAdvisory(result);
145
+ }
146
+ log('release');
147
+ const releaseResult = await checkReleaseLabelExists(target);
148
+ record(report, 'release', releaseResult, 'warn');
149
+ if (!json)
150
+ printAdvisory(releaseResult);
151
+ if (json) {
152
+ process.stdout.write(`${JSON.stringify({ status: status === 0 ? 'ok' : 'fail', checks: report }, null, 2)}\n`);
153
+ }
154
+ return status === 0 ? 0 : 1;
155
+ }
156
+ //# sourceMappingURL=doctor.js.map