@readme/cli 0.0.26

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 (144) hide show
  1. package/README.md +55 -0
  2. package/bin/readme.js +8 -0
  3. package/package.json +58 -0
  4. package/src/bootstrap.js +97 -0
  5. package/src/cli.js +189 -0
  6. package/src/commands/dev.js +119 -0
  7. package/src/commands/eyes.js +37 -0
  8. package/src/commands/import.js +2565 -0
  9. package/src/commands/lint.js +70 -0
  10. package/src/commands/oas-sync.js +364 -0
  11. package/src/commands/oas-validate.js +208 -0
  12. package/src/commands/play.js +17 -0
  13. package/src/commands/pretty.js +133 -0
  14. package/src/commands/setup.js +256 -0
  15. package/src/commands/versions.js +81 -0
  16. package/src/dev/.next/app-build-manifest.json +20 -0
  17. package/src/dev/.next/build-manifest.json +31 -0
  18. package/src/dev/.next/cache/.rscinfo +1 -0
  19. package/src/dev/.next/cache/next-devtools-config.json +1 -0
  20. package/src/dev/.next/cache/webpack/client-development/0.pack.gz +0 -0
  21. package/src/dev/.next/cache/webpack/client-development/1.pack.gz +0 -0
  22. package/src/dev/.next/cache/webpack/client-development/10.pack.gz +0 -0
  23. package/src/dev/.next/cache/webpack/client-development/11.pack.gz +0 -0
  24. package/src/dev/.next/cache/webpack/client-development/2.pack.gz +0 -0
  25. package/src/dev/.next/cache/webpack/client-development/3.pack.gz +0 -0
  26. package/src/dev/.next/cache/webpack/client-development/3.pack.gz_ +0 -0
  27. package/src/dev/.next/cache/webpack/client-development/4.pack.gz +0 -0
  28. package/src/dev/.next/cache/webpack/client-development/5.pack.gz +0 -0
  29. package/src/dev/.next/cache/webpack/client-development/5.pack.gz_ +0 -0
  30. package/src/dev/.next/cache/webpack/client-development/6.pack.gz +0 -0
  31. package/src/dev/.next/cache/webpack/client-development/7.pack.gz +0 -0
  32. package/src/dev/.next/cache/webpack/client-development/7.pack.gz_ +0 -0
  33. package/src/dev/.next/cache/webpack/client-development/8.pack.gz +0 -0
  34. package/src/dev/.next/cache/webpack/client-development/9.pack.gz +0 -0
  35. package/src/dev/.next/cache/webpack/client-development/index.pack.gz.old +0 -0
  36. package/src/dev/.next/cache/webpack/client-development-fallback/0.pack.gz +0 -0
  37. package/src/dev/.next/cache/webpack/client-development-fallback/1.pack.gz +0 -0
  38. package/src/dev/.next/cache/webpack/client-development-fallback/index.pack.gz +0 -0
  39. package/src/dev/.next/cache/webpack/client-development-fallback/index.pack.gz.old +0 -0
  40. package/src/dev/.next/cache/webpack/edge-server-development/0.pack.gz +0 -0
  41. package/src/dev/.next/cache/webpack/edge-server-development/1.pack.gz +0 -0
  42. package/src/dev/.next/cache/webpack/edge-server-development/index.pack.gz +0 -0
  43. package/src/dev/.next/cache/webpack/edge-server-development/index.pack.gz.old +0 -0
  44. package/src/dev/.next/cache/webpack/server-development/0.pack.gz +0 -0
  45. package/src/dev/.next/cache/webpack/server-development/1.pack.gz +0 -0
  46. package/src/dev/.next/cache/webpack/server-development/10.pack.gz +0 -0
  47. package/src/dev/.next/cache/webpack/server-development/11.pack.gz +0 -0
  48. package/src/dev/.next/cache/webpack/server-development/12.pack.gz +0 -0
  49. package/src/dev/.next/cache/webpack/server-development/13.pack.gz +0 -0
  50. package/src/dev/.next/cache/webpack/server-development/14.pack.gz +0 -0
  51. package/src/dev/.next/cache/webpack/server-development/15.pack.gz +0 -0
  52. package/src/dev/.next/cache/webpack/server-development/2.pack.gz +0 -0
  53. package/src/dev/.next/cache/webpack/server-development/2.pack.gz_ +0 -0
  54. package/src/dev/.next/cache/webpack/server-development/3.pack.gz +0 -0
  55. package/src/dev/.next/cache/webpack/server-development/3.pack.gz_ +0 -0
  56. package/src/dev/.next/cache/webpack/server-development/4.pack.gz +0 -0
  57. package/src/dev/.next/cache/webpack/server-development/5.pack.gz +0 -0
  58. package/src/dev/.next/cache/webpack/server-development/6.pack.gz +0 -0
  59. package/src/dev/.next/cache/webpack/server-development/6.pack.gz_ +0 -0
  60. package/src/dev/.next/cache/webpack/server-development/7.pack.gz +0 -0
  61. package/src/dev/.next/cache/webpack/server-development/7.pack.gz_ +0 -0
  62. package/src/dev/.next/cache/webpack/server-development/8.pack.gz +0 -0
  63. package/src/dev/.next/cache/webpack/server-development/9.pack.gz +0 -0
  64. package/src/dev/.next/cache/webpack/server-development/9.pack.gz_ +0 -0
  65. package/src/dev/.next/cache/webpack/server-development/index.pack.gz +0 -0
  66. package/src/dev/.next/cache/webpack/server-development/index.pack.gz.old +0 -0
  67. package/src/dev/.next/package.json +1 -0
  68. package/src/dev/.next/prerender-manifest.json +11 -0
  69. package/src/dev/.next/react-loadable-manifest.json +1 -0
  70. package/src/dev/.next/routes-manifest.json +1 -0
  71. package/src/dev/.next/server/app/[...slug]/page.js +360 -0
  72. package/src/dev/.next/server/app/[...slug]/page_client-reference-manifest.js +1 -0
  73. package/src/dev/.next/server/app/page.js +349 -0
  74. package/src/dev/.next/server/app/page_client-reference-manifest.js +1 -0
  75. package/src/dev/.next/server/app-paths-manifest.json +3 -0
  76. package/src/dev/.next/server/edge-runtime-webpack.js +1151 -0
  77. package/src/dev/.next/server/interception-route-rewrite-manifest.js +1 -0
  78. package/src/dev/.next/server/middleware-build-manifest.js +33 -0
  79. package/src/dev/.next/server/middleware-manifest.json +32 -0
  80. package/src/dev/.next/server/middleware-react-loadable-manifest.js +1 -0
  81. package/src/dev/.next/server/middleware.js +1113 -0
  82. package/src/dev/.next/server/next-font-manifest.js +1 -0
  83. package/src/dev/.next/server/next-font-manifest.json +1 -0
  84. package/src/dev/.next/server/pages-manifest.json +5 -0
  85. package/src/dev/.next/server/server-reference-manifest.js +1 -0
  86. package/src/dev/.next/server/server-reference-manifest.json +5 -0
  87. package/src/dev/.next/server/static/webpack/633457081244afec._.hot-update.json +1 -0
  88. package/src/dev/.next/server/vendor-chunks/@readme.js +25 -0
  89. package/src/dev/.next/server/vendor-chunks/@swc.js +55 -0
  90. package/src/dev/.next/server/vendor-chunks/next.js +3659 -0
  91. package/src/dev/.next/server/webpack-runtime.js +209 -0
  92. package/src/dev/.next/static/chunks/app/[...slug]/loading.js +28 -0
  93. package/src/dev/.next/static/chunks/app/[...slug]/page.js +28 -0
  94. package/src/dev/.next/static/chunks/app/layout.js +171 -0
  95. package/src/dev/.next/static/chunks/app/page.js +28 -0
  96. package/src/dev/.next/static/chunks/app-pages-internals.js +182 -0
  97. package/src/dev/.next/static/chunks/main-app.js +1882 -0
  98. package/src/dev/.next/static/chunks/polyfills.js +1 -0
  99. package/src/dev/.next/static/chunks/webpack.js +1393 -0
  100. package/src/dev/.next/static/css/app/layout.css +559 -0
  101. package/src/dev/.next/static/development/_buildManifest.js +1 -0
  102. package/src/dev/.next/static/development/_ssgManifest.js +1 -0
  103. package/src/dev/.next/static/webpack/633457081244afec._.hot-update.json +1 -0
  104. package/src/dev/.next/static/webpack/ec52a3fce0f78db0.webpack.hot-update.json +1 -0
  105. package/src/dev/.next/static/webpack/webpack.ec52a3fce0f78db0.hot-update.js +12 -0
  106. package/src/dev/.next/trace +21 -0
  107. package/src/dev/.next/types/app/[...slug]/page.ts +84 -0
  108. package/src/dev/.next/types/app/layout.ts +84 -0
  109. package/src/dev/.next/types/app/page.ts +84 -0
  110. package/src/dev/.next/types/cache-life.d.ts +141 -0
  111. package/src/dev/.next/types/package.json +1 -0
  112. package/src/dev/.next/types/routes.d.ts +55 -0
  113. package/src/dev/app/Sidebar.js +149 -0
  114. package/src/dev/app/[...slug]/loading.js +16 -0
  115. package/src/dev/app/[...slug]/page.js +43 -0
  116. package/src/dev/app/globals.css +167 -0
  117. package/src/dev/app/layout.js +73 -0
  118. package/src/dev/app/page.js +19 -0
  119. package/src/dev/lib/docs.js +337 -0
  120. package/src/dev/middleware.js +7 -0
  121. package/src/dev/next.config.mjs +22 -0
  122. package/src/index.js +12 -0
  123. package/src/prompts/index.js +352 -0
  124. package/src/utils/claude.js +15 -0
  125. package/src/utils/eyes.js +365 -0
  126. package/src/utils/git.js +143 -0
  127. package/src/utils/lint.js +99 -0
  128. package/src/utils/reporter.js +319 -0
  129. package/src/utils/setup-templates.js +323 -0
  130. package/src/utils/styles.js +50 -0
  131. package/src/utils/tamagotchi.js +1139 -0
  132. package/src/utils/tips.js +90 -0
  133. package/src/validators/components.js +230 -0
  134. package/src/validators/content.js +53 -0
  135. package/src/validators/duplicates.js +45 -0
  136. package/src/validators/frontmatter.js +247 -0
  137. package/src/validators/links.js +68 -0
  138. package/src/validators/nesting.js +50 -0
  139. package/src/validators/numbering.js +136 -0
  140. package/src/validators/oas-reference.js +126 -0
  141. package/src/validators/oas-schema.js +106 -0
  142. package/src/validators/ordering.js +121 -0
  143. package/src/validators/recipes.js +143 -0
  144. package/vendor/TOOLS.md +19 -0
@@ -0,0 +1,133 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { createRequire } from 'node:module';
4
+ import { query } from '@anthropic-ai/claude-agent-sdk';
5
+ import matter from 'gray-matter';
6
+ import ora from 'ora';
7
+ import { collectFiles } from '../utils/lint.js';
8
+ import { prettifyPagePrompt, stripCodeFences } from '../prompts/index.js';
9
+ import { printHeader, isAgenticCli } from '../utils/eyes.js';
10
+ import * as styles from '../utils/styles.js';
11
+
12
+ const require = createRequire(import.meta.url);
13
+ const pkg = require('../../package.json');
14
+
15
+ export const command = 'pretty';
16
+ export const order = 2;
17
+ export const description = 'Polish docs into ReadMe-ready MDX with Claude';
18
+ export const beta = true;
19
+
20
+ export function args(cmd) {
21
+ cmd.option('--model <name>', 'Claude model alias: haiku, sonnet, opus', 'sonnet');
22
+ cmd.option('--dry-run', 'Show what would change without writing files');
23
+ }
24
+
25
+ /**
26
+ * Send one page through Claude using the prettify system prompt and parse the
27
+ * JSON response. Returns the parsed object or throws on failure.
28
+ */
29
+ async function prettifyPage({ source, title, relativePath, model }) {
30
+ const { systemPrompt, userPrompt } = prettifyPagePrompt({ source, title, relativePath });
31
+
32
+ let text = '';
33
+ for await (const message of query({
34
+ prompt: userPrompt,
35
+ options: {
36
+ systemPrompt,
37
+ allowedTools: [],
38
+ ...(model ? { model } : {}),
39
+ },
40
+ })) {
41
+ if (message.type === 'assistant' && message.message?.content) {
42
+ for (const block of message.message.content) {
43
+ if (block.type === 'text' && block.text) text += block.text;
44
+ }
45
+ } else if (message.type === 'result') {
46
+ if (message.subtype && message.subtype !== 'success') {
47
+ throw new Error(`${message.subtype}${message.error?.message ? ' — ' + message.error.message : ''}`);
48
+ }
49
+ break;
50
+ }
51
+ }
52
+
53
+ const stripped = stripCodeFences(text);
54
+ try {
55
+ return JSON.parse(stripped);
56
+ } catch (e) {
57
+ throw new Error(`invalid JSON (${e.message}); first 200 chars: ${stripped.slice(0, 200)}`);
58
+ }
59
+ }
60
+
61
+ export async function run(options, _cmd, ctx) {
62
+ const { gitRoot } = ctx;
63
+
64
+ if (!isAgenticCli()) {
65
+ printHeader({ version: pkg.version, binName: styles.binName(), indent: ' ' });
66
+ console.log();
67
+ }
68
+
69
+ const files = collectFiles(gitRoot);
70
+ if (files.length === 0) {
71
+ styles.warning('No docs files found to prettify.');
72
+ return;
73
+ }
74
+
75
+ styles.info(
76
+ `Prettifying ${styles.bold(String(files.length))} file${files.length === 1 ? '' : 's'} with ${styles.bold(options.model)}${options.dryRun ? styles.dim(' (dry run)') : ''}.`,
77
+ );
78
+ console.log();
79
+
80
+ const spinner = ora({ color: 'blue' }).start();
81
+ let updated = 0;
82
+ let unchanged = 0;
83
+ const failures = [];
84
+
85
+ for (const relativePath of files) {
86
+ spinner.text = relativePath;
87
+ const filePath = path.join(gitRoot, relativePath);
88
+ const original = fs.readFileSync(filePath, 'utf-8');
89
+ const parsed = matter(original);
90
+
91
+ try {
92
+ const result = await prettifyPage({
93
+ source: parsed.content,
94
+ title: parsed.data?.title,
95
+ relativePath,
96
+ model: options.model,
97
+ });
98
+
99
+ if (typeof result?.body !== 'string') {
100
+ throw new Error('response missing "body" field');
101
+ }
102
+
103
+ const newFm = { ...parsed.data };
104
+ if (result.excerpt && !newFm.excerpt) newFm.excerpt = result.excerpt;
105
+ const next = matter.stringify(result.body, newFm);
106
+
107
+ if (next === original) {
108
+ unchanged++;
109
+ } else {
110
+ if (!options.dryRun) fs.writeFileSync(filePath, next, 'utf-8');
111
+ updated++;
112
+ }
113
+ } catch (err) {
114
+ failures.push({ relativePath, message: err.message || String(err) });
115
+ }
116
+ }
117
+
118
+ spinner.stop();
119
+
120
+ console.log();
121
+ const verb = options.dryRun ? 'would update' : 'updated';
122
+ styles.ok(
123
+ `${styles.bold(String(updated))} ${verb} · ${styles.bold(String(unchanged))} unchanged${failures.length ? ` · ${styles.bold(String(failures.length))} failed` : ''}`,
124
+ );
125
+
126
+ if (failures.length > 0) {
127
+ console.log();
128
+ for (const f of failures) {
129
+ console.log(` ${styles.err('●')} ${styles.bold(f.relativePath)} ${styles.dim('— ' + f.message)}`);
130
+ }
131
+ process.exit(1);
132
+ }
133
+ }
@@ -0,0 +1,256 @@
1
+ import { execSync } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import readline from 'node:readline';
5
+ import * as styles from '../utils/styles.js';
6
+ import {
7
+ PLATFORMS,
8
+ detectExistingCi,
9
+ detectPlatform,
10
+ usesBlacksmith,
11
+ } from '../utils/git.js';
12
+ import { templateFor } from '../utils/setup-templates.js';
13
+
14
+ // Detect the user's CI platform at module load so the top-level `--help`
15
+ // can advertise the right `setup:<platform>` form (e.g. `setup:github` for
16
+ // a GitHub repo). Falls back to the generic `setup:ci`.
17
+ function quickGitRoot() {
18
+ try {
19
+ return execSync('git rev-parse --show-toplevel', {
20
+ encoding: 'utf-8',
21
+ stdio: ['pipe', 'pipe', 'pipe'],
22
+ }).trim();
23
+ } catch {
24
+ return null;
25
+ }
26
+ }
27
+
28
+ const _root = quickGitRoot();
29
+ const _detected = _root ? detectPlatform(_root).recommended : null;
30
+ const _hasExistingCi = _root ? detectExistingCi(_root).length > 0 : false;
31
+ const _primaryName = _detected ? `setup:${_detected}` : 'setup:ci';
32
+ const _primaryLabel = _detected ? PLATFORMS[_detected].label : 'a CI workflow';
33
+
34
+ export const command = _primaryName;
35
+ export const order = 5;
36
+ export const category = 'Linting';
37
+ export const description = `Set up ${_primaryLabel} to lint your docs on every PR`;
38
+ // Skip the hint when existing CI is detected — they've already chosen a platform.
39
+ export const helpHint = _hasExistingCi
40
+ ? null
41
+ : `Using something else?\nRun \`${styles.binName()} setup --help\` to see all supported CI platforms.`;
42
+
43
+ // Hidden aliases cover every other form: bare `setup` (with optional positional),
44
+ // the generic `setup:ci`, and one entry per platform. Whichever form is the
45
+ // primary above is filtered out so it isn't double-registered.
46
+ const ALL_FORMS = [
47
+ 'setup [platform]',
48
+ 'setup:ci',
49
+ ...Object.keys(PLATFORMS).map((k) => `setup:${k}`),
50
+ ];
51
+ export const aliases = ALL_FORMS.filter((a) => a.split(' ')[0] !== _primaryName);
52
+
53
+ export function args(cmd) {
54
+ cmd.option('--blacksmith', 'Use Blacksmith runners (GitHub Actions only)');
55
+ cmd.option('-y, --yes', 'Skip confirmation prompt');
56
+
57
+ cmd.addHelpText('after', () => {
58
+ const bin = styles.binName();
59
+ const cmdStrs = Object.keys(PLATFORMS).map((k) => `${bin} setup:${k}`);
60
+ const cmdWidth = Math.max(...cmdStrs.map((s) => s.length));
61
+ const labelWidth = Math.max(...Object.values(PLATFORMS).map((d) => d.label.length));
62
+ const rows = Object.entries(PLATFORMS).map(([key, def], i) => {
63
+ const cmdStr = cmdStrs[i].padEnd(cmdWidth);
64
+ const label = def.label.padEnd(labelWidth);
65
+ const marker = key === _detected ? styles.success('●') : ' ';
66
+ return ` ${marker} ${styles.orange(cmdStr)} ${styles.dim('—')} ${label} ${styles.dim(def.workflowFile)}`;
67
+ });
68
+ const examples = [
69
+ [`${bin} setup`, '# auto-detect and confirm'],
70
+ [`${bin} setup:github --blacksmith`, '# GitHub Actions on Blacksmith runners'],
71
+ [`${bin} setup:gitlab -y`, '# skip the confirmation prompt'],
72
+ ];
73
+ const exWidth = Math.max(...examples.map(([c]) => c.length));
74
+ const exRows = examples.map(([c, note]) => ` ${styles.orange(c.padEnd(exWidth))} ${styles.dim(note)}`);
75
+ const detectedLine = _detected
76
+ ? ` ${styles.dim('Detected:')} ${styles.bold(PLATFORMS[_detected].label)} ${styles.dim('— recommend')} ${styles.orange(`${bin} setup:${_detected}`)}`
77
+ : ` ${styles.dim('Run')} ${styles.orange(`${bin} setup`)} ${styles.dim('to auto-detect from .git/config + existing CI files.')}`;
78
+ return [
79
+ '',
80
+ `${styles.bold('Auto-detection:')}`,
81
+ detectedLine,
82
+ '',
83
+ `${styles.bold('Platforms:')}`,
84
+ ...rows,
85
+ '',
86
+ `${styles.bold('Examples:')}`,
87
+ ...exRows,
88
+ '',
89
+ ].join('\n');
90
+ });
91
+ }
92
+
93
+ export async function run(...callArgs) {
94
+ // Action signature varies by which form was invoked:
95
+ // `setup:github` → (opts, cmd, ctx)
96
+ // `setup [platform]` → (platformPositional, opts, cmd, ctx)
97
+ // ctx is always last (added by cli.js bootstrap).
98
+ const ctx = callArgs.pop();
99
+ const cmd = callArgs.pop();
100
+ const opts = callArgs.pop();
101
+ const positional = callArgs[0];
102
+
103
+ // Pull platform from the matched command name, or fall back to the positional.
104
+ const cmdName = cmd.name();
105
+ let platformArg = null;
106
+ if (cmdName.startsWith('setup:') && cmdName !== 'setup:ci') {
107
+ platformArg = cmdName.slice('setup:'.length);
108
+ } else if (positional) {
109
+ platformArg = positional;
110
+ }
111
+
112
+ const { gitRoot } = ctx;
113
+
114
+ // 1. Resolve which platform we're setting up.
115
+ let platform = normalizePlatform(platformArg);
116
+ let detection = null;
117
+
118
+ if (!platform) {
119
+ detection = detectPlatform(gitRoot);
120
+ platform = detection.recommended;
121
+
122
+ if (!platform) {
123
+ printDetectionFailure();
124
+ process.exit(1);
125
+ }
126
+ } else if (!PLATFORMS[platform]) {
127
+ styles.error(`Unknown platform: ${styles.bold(platformArg)}`);
128
+ styles.info(`Available: ${Object.keys(PLATFORMS).join(', ')}`);
129
+ process.exit(1);
130
+ }
131
+
132
+ // 2. Validate platform-specific options.
133
+ if (opts.blacksmith && platform !== 'github') {
134
+ styles.error('--blacksmith is only valid with GitHub Actions.');
135
+ process.exit(1);
136
+ }
137
+
138
+ let useBlacksmith = !!opts.blacksmith;
139
+ if (platform === 'github' && !opts.blacksmith && usesBlacksmith(gitRoot)) {
140
+ useBlacksmith = true;
141
+ }
142
+
143
+ const def = PLATFORMS[platform];
144
+ const workflowPath = path.join(gitRoot, def.workflowFile);
145
+ const isOverwrite = fs.existsSync(workflowPath);
146
+
147
+ // 3. Show what will happen.
148
+ console.log();
149
+ console.log(` ${styles.heading(`${def.label} Setup`)}`);
150
+ console.log();
151
+
152
+ if (detection) printDetectionSummary(detection, platform);
153
+
154
+ console.log(` This will create a workflow that runs on every pull request:`);
155
+ console.log();
156
+ console.log(` ${styles.success('✔')} ${styles.bold('Lint docs')} — runs ${styles.orange(`${styles.binName()} lint`)} and posts results as a PR comment`);
157
+ if (platform === 'github') {
158
+ console.log(` ${styles.success('✔')} ${styles.bold('OAS change detection')} — flags modified OpenAPI spec files and suggests syncing`);
159
+ console.log(` ${styles.success('✔')} ${styles.bold('Auto-fix base branch')} — redirects PRs from ${styles.orange('main')} to the correct version branch`);
160
+ if (useBlacksmith) {
161
+ console.log(` ${styles.success('✔')} ${styles.bold('Blacksmith runner')} — uses ${styles.orange('blacksmith-2vcpu-ubuntu-2404')} instead of ${styles.orange('ubuntu-latest')}`);
162
+ }
163
+ }
164
+ console.log();
165
+ console.log(` ${styles.dim('Creates:')} ${path.relative(gitRoot, workflowPath)}`);
166
+
167
+ printPostSetupNotes(platform);
168
+ console.log();
169
+
170
+ // 4. Confirm.
171
+ if (!opts.yes) {
172
+ const prompt = isOverwrite
173
+ ? 'This will overwrite the existing workflow. Continue?'
174
+ : 'Set up this workflow?';
175
+ const confirmed = await confirm(prompt);
176
+ if (!confirmed) {
177
+ styles.info('Setup cancelled.');
178
+ return;
179
+ }
180
+ }
181
+
182
+ // 5. Write.
183
+ fs.mkdirSync(path.dirname(workflowPath), { recursive: true });
184
+ fs.writeFileSync(workflowPath, templateFor(platform, { blacksmith: useBlacksmith }));
185
+
186
+ console.log();
187
+ styles.ok(`Created ${def.label} workflow!`);
188
+ console.log();
189
+ styles.info('Commit and push this file to start linting PRs automatically.');
190
+ }
191
+
192
+ function normalizePlatform(input) {
193
+ if (!input) return null;
194
+ const key = input.toLowerCase();
195
+ if (key === 'gh') return 'github';
196
+ if (key === 'gl') return 'gitlab';
197
+ if (key === 'bb' || key === 'bitbucket-pipelines') return 'bitbucket';
198
+ if (key === 'circle' || key === 'circle-ci') return 'circleci';
199
+ if (key === 'mint') return 'rwx';
200
+ return key;
201
+ }
202
+
203
+ function printDetectionSummary(detection, chosen) {
204
+ const lines = [];
205
+ if (detection.existing.length > 0) {
206
+ const labels = detection.existing.map((k) => PLATFORMS[k].label).join(', ');
207
+ lines.push(`${styles.dim('Detected existing CI:')} ${labels}`);
208
+ }
209
+ if (detection.remote) {
210
+ lines.push(`${styles.dim('Detected git remote:')} ${PLATFORMS[detection.remote].label}`);
211
+ }
212
+ lines.push(`${styles.dim('Setting up:')} ${styles.bold(PLATFORMS[chosen].label)}`);
213
+ for (const l of lines) console.log(` ${l}`);
214
+ console.log();
215
+ }
216
+
217
+ function printDetectionFailure() {
218
+ console.log();
219
+ styles.error("Couldn't detect a CI platform for this repo.");
220
+ console.log();
221
+ console.log(` ${styles.dim('No matching git remote and no existing CI config found.')}`);
222
+ console.log();
223
+ console.log(` Specify a platform explicitly:`);
224
+ for (const [key, def] of Object.entries(PLATFORMS)) {
225
+ console.log(` ${styles.orange(`${styles.binName()} setup:${key}`)} ${styles.dim('—')} ${def.label}`);
226
+ }
227
+ console.log();
228
+ }
229
+
230
+ function printPostSetupNotes(platform) {
231
+ const notes = {
232
+ gitlab: ` ${styles.dim('Required:')} CI/CD variable ${styles.bold('GITLAB_TOKEN')} with ${styles.bold('api')} scope`,
233
+ bitbucket: ` ${styles.dim('Required:')} repository variables ${styles.bold('BITBUCKET_USERNAME')} and ${styles.bold('BITBUCKET_TOKEN')} (app password with ${styles.bold('pullrequest:write')})`,
234
+ circleci: ` ${styles.dim('Required:')} project env var ${styles.bold('CIRCLE_PROJECT_GITHUB_TOKEN')} with PR comment permission`,
235
+ rwx: ` ${styles.dim('Required:')} vault secret ${styles.bold('GITHUB_TOKEN')} with PR comment permission`,
236
+ };
237
+ if (notes[platform]) {
238
+ console.log();
239
+ console.log(notes[platform]);
240
+ }
241
+ }
242
+
243
+ function confirm(message) {
244
+ const rl = readline.createInterface({
245
+ input: process.stdin,
246
+ output: process.stdout,
247
+ });
248
+
249
+ return new Promise((resolve) => {
250
+ rl.question(`${styles.brand('?')} ${message} ${styles.dim('(Y/n)')} `, (answer) => {
251
+ rl.close();
252
+ const val = answer.trim().toLowerCase();
253
+ resolve(val === '' || val === 'y' || val === 'yes');
254
+ });
255
+ });
256
+ }
@@ -0,0 +1,81 @@
1
+ import { execSync } from 'node:child_process';
2
+ import * as styles from '../utils/styles.js';
3
+
4
+ export const command = 'versions';
5
+ export const order = 4;
6
+ export const category = 'Other';
7
+ export const description = 'List all doc versions and their branches';
8
+
9
+ const VERSION_RE = /^v\d+(\.\d+)*$/;
10
+ const SUB_BRANCH_RE = /^(v\d+(?:\.\d+)*)_(.+)$/;
11
+
12
+ export function run(_options, _cmd, ctx) {
13
+ const { gitRoot } = ctx;
14
+
15
+ const raw = execSync('git branch -a --format="%(refname:short)"', {
16
+ cwd: gitRoot,
17
+ encoding: 'utf-8',
18
+ stdio: ['pipe', 'pipe', 'pipe'],
19
+ }).trim();
20
+
21
+ const branches = raw.split('\n').map((b) => b.trim()).filter(Boolean);
22
+
23
+ // Strip "origin/" prefix and deduplicate.
24
+ const seen = new Set();
25
+ const cleaned = [];
26
+ for (const b of branches) {
27
+ const name = b.replace(/^origin\//, '');
28
+ if (!seen.has(name)) {
29
+ seen.add(name);
30
+ cleaned.push(name);
31
+ }
32
+ }
33
+
34
+ // Group: version branches and their sub-branches.
35
+ const versions = new Map();
36
+ const subBranches = [];
37
+
38
+ for (const name of cleaned) {
39
+ if (VERSION_RE.test(name)) {
40
+ versions.set(name, []);
41
+ } else {
42
+ const match = name.match(SUB_BRANCH_RE);
43
+ if (match) {
44
+ subBranches.push({ parent: match[1], name: match[2], full: name });
45
+ }
46
+ }
47
+ }
48
+
49
+ // Attach sub-branches to their parent version.
50
+ for (const sub of subBranches) {
51
+ if (versions.has(sub.parent)) {
52
+ versions.get(sub.parent).push(sub);
53
+ }
54
+ }
55
+
56
+ // Sort versions by semver-ish ordering (descending).
57
+ const sorted = [...versions.entries()].sort((a, b) => {
58
+ const aParts = a[0].slice(1).split('.').map(Number);
59
+ const bParts = b[0].slice(1).split('.').map(Number);
60
+ for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
61
+ const diff = (bParts[i] || 0) - (aParts[i] || 0);
62
+ if (diff !== 0) return diff;
63
+ }
64
+ return 0;
65
+ });
66
+
67
+ console.log();
68
+ console.log(` ${styles.logo()} ${styles.dim('versions')}`);
69
+ console.log();
70
+
71
+ for (const [version, subs] of sorted) {
72
+ console.log(` ${styles.bold(version)}`);
73
+ for (let i = 0; i < subs.length; i++) {
74
+ const isLast = i === subs.length - 1;
75
+ const connector = isLast ? '└─' : '├─';
76
+ console.log(` ${styles.dim(connector)} ${styles.dim(version + '_')}${subs[i].name} ${styles.dim('(branch)')}`);
77
+ }
78
+ }
79
+
80
+ console.log();
81
+ }
@@ -0,0 +1,20 @@
1
+ {
2
+ "pages": {
3
+ "/layout": [
4
+ "static/chunks/webpack.js",
5
+ "static/chunks/main-app.js",
6
+ "static/css/app/layout.css",
7
+ "static/chunks/app/layout.js"
8
+ ],
9
+ "/[...slug]/loading": [
10
+ "static/chunks/webpack.js",
11
+ "static/chunks/main-app.js",
12
+ "static/chunks/app/[...slug]/loading.js"
13
+ ],
14
+ "/[...slug]/page": [
15
+ "static/chunks/webpack.js",
16
+ "static/chunks/main-app.js",
17
+ "static/chunks/app/[...slug]/page.js"
18
+ ]
19
+ }
20
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "polyfillFiles": [
3
+ "static/chunks/polyfills.js"
4
+ ],
5
+ "devFiles": [
6
+ "static/chunks/react-refresh.js"
7
+ ],
8
+ "ampDevFiles": [],
9
+ "lowPriorityFiles": [
10
+ "static/development/_buildManifest.js",
11
+ "static/development/_ssgManifest.js"
12
+ ],
13
+ "rootMainFiles": [
14
+ "static/chunks/webpack.js",
15
+ "static/chunks/main-app.js"
16
+ ],
17
+ "rootMainFilesTree": {},
18
+ "pages": {
19
+ "/_app": [
20
+ "static/chunks/webpack.js",
21
+ "static/chunks/main.js",
22
+ "static/chunks/pages/_app.js"
23
+ ],
24
+ "/_error": [
25
+ "static/chunks/webpack.js",
26
+ "static/chunks/main.js",
27
+ "static/chunks/pages/_error.js"
28
+ ]
29
+ },
30
+ "ampFirstPages": []
31
+ }
@@ -0,0 +1 @@
1
+ {"encryption.key":"3SIKRvTdjH2KvDXOUMwtVkaVmj4v5oCsYq33R2HYXtM=","encryption.expire_at":1772814750891}
@@ -0,0 +1 @@
1
+ {"type": "commonjs"}
@@ -0,0 +1,11 @@
1
+ {
2
+ "version": 4,
3
+ "routes": {},
4
+ "dynamicRoutes": {},
5
+ "notFoundRoutes": [],
6
+ "preview": {
7
+ "previewModeId": "b628b03ee18bb42bb63fcc51ca49946f",
8
+ "previewModeSigningKey": "f82f45cc5833fe189f9cc960b8dd1be2c6c51a3c05cf345f3497ced03b8c7b0d",
9
+ "previewModeEncryptionKey": "ab192619b9dd28eb198eda117db9c62df8ca0dba79469500b34cdcdf2b290da3"
10
+ }
11
+ }