@redpanda-data/docs-extensions-and-macros 4.13.0 → 4.13.2

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 (49) hide show
  1. package/bin/doc-tools-mcp.js +15 -3
  2. package/bin/doc-tools.js +767 -2088
  3. package/bin/mcp-tools/property-docs.js +18 -0
  4. package/bin/mcp-tools/rpcn-docs.js +28 -3
  5. package/cli-utils/antora-utils.js +53 -2
  6. package/cli-utils/dependencies.js +313 -0
  7. package/cli-utils/diff-utils.js +273 -0
  8. package/cli-utils/doc-tools-utils.js +54 -0
  9. package/extensions/algolia-indexer/generate-index.js +134 -102
  10. package/extensions/algolia-indexer/index.js +70 -38
  11. package/extensions/collect-bloblang-samples.js +2 -1
  12. package/extensions/generate-rp-connect-categories.js +126 -67
  13. package/extensions/generate-rp-connect-info.js +291 -137
  14. package/macros/rp-connect-components.js +34 -5
  15. package/mcp/CLI_INTERFACE.adoc +384 -0
  16. package/mcp/COSTS.adoc +167 -0
  17. package/mcp/DEVELOPMENT.adoc +726 -0
  18. package/mcp/README.adoc +172 -0
  19. package/mcp/USER_GUIDE.adoc +1392 -0
  20. package/mcp/WRITER_EXTENSION_GUIDE.adoc +814 -0
  21. package/mcp/prompts/README.adoc +183 -0
  22. package/mcp/prompts/property-docs-guide.md +283 -0
  23. package/mcp/prompts/review-for-style.md +128 -0
  24. package/mcp/prompts/rpcn-connector-docs-guide.md +126 -0
  25. package/mcp/prompts/write-new-guide.md +222 -0
  26. package/mcp/team-standards/style-guide.md +321 -0
  27. package/mcp/templates/README.adoc +212 -0
  28. package/mcp/templates/prompt-review-template.md +80 -0
  29. package/mcp/templates/prompt-write-template.md +110 -0
  30. package/mcp/templates/resource-template.md +76 -0
  31. package/package.json +8 -5
  32. package/tools/add-commercial-names.js +207 -0
  33. package/tools/generate-cli-docs.js +6 -2
  34. package/tools/get-console-version.js +5 -0
  35. package/tools/get-redpanda-version.js +5 -0
  36. package/tools/property-extractor/compare-properties.js +3 -3
  37. package/tools/property-extractor/generate-handlebars-docs.js +14 -14
  38. package/tools/property-extractor/generate-pr-summary.js +46 -0
  39. package/tools/property-extractor/pr-summary-formatter.js +375 -0
  40. package/tools/redpanda-connect/README.adoc +403 -38
  41. package/tools/redpanda-connect/connector-binary-analyzer.js +588 -0
  42. package/tools/redpanda-connect/generate-rpcn-connector-docs.js +97 -34
  43. package/tools/redpanda-connect/parse-csv-connectors.js +1 -1
  44. package/tools/redpanda-connect/pr-summary-formatter.js +601 -0
  45. package/tools/redpanda-connect/report-delta.js +69 -2
  46. package/tools/redpanda-connect/rpcn-connector-docs-handler.js +1180 -0
  47. package/tools/redpanda-connect/templates/connector.hbs +38 -0
  48. package/tools/redpanda-connect/templates/intro.hbs +0 -20
  49. package/tools/redpanda-connect/update-nav.js +205 -0
@@ -0,0 +1,207 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const glob = require('glob');
6
+
7
+ // Commercial name mappings based on connector patterns
8
+ const commercialNameMappings = {
9
+ // AWS services
10
+ 'aws_s3': 'Amazon S3, AWS S3, S3, Simple Storage Service',
11
+ 'aws_kinesis': 'Amazon Kinesis, AWS Kinesis, Kinesis',
12
+ 'aws_sqs': 'Amazon SQS, AWS SQS, SQS, Simple Queue Service',
13
+ 'aws_sns': 'Amazon SNS, AWS SNS, SNS, Simple Notification Service',
14
+ 'aws_dynamodb': 'Amazon DynamoDB, AWS DynamoDB, DynamoDB',
15
+ 'aws_kinesis_firehose': 'Amazon Kinesis Firehose, AWS Kinesis Firehose, Kinesis Firehose',
16
+ 'aws_lambda': 'Amazon Lambda, AWS Lambda, Lambda',
17
+ 'aws_cloudwatch': 'Amazon CloudWatch, AWS CloudWatch, CloudWatch',
18
+
19
+ // Message queues
20
+ 'amqp_0_9': 'RabbitMQ, AMQP',
21
+ 'amqp_1': 'RabbitMQ, AMQP, Apache Qpid',
22
+ 'kafka': 'Apache Kafka, Kafka',
23
+ 'kafka_franz': 'Apache Kafka, Kafka',
24
+ 'nats': 'NATS, NATS.io',
25
+ 'nats_jetstream': 'NATS JetStream, NATS',
26
+ 'nats_stream': 'NATS Streaming, NATS',
27
+ 'pulsar': 'Apache Pulsar, Pulsar',
28
+ 'redis_pubsub': 'Redis Pub/Sub, Redis',
29
+ 'redis_streams': 'Redis Streams, Redis',
30
+ 'redis_list': 'Redis Lists, Redis',
31
+
32
+ // Databases - general patterns
33
+ 'mongodb': 'MongoDB, Mongo',
34
+ 'cassandra': 'Apache Cassandra, Cassandra',
35
+ 'elasticsearch': 'Elasticsearch, Elastic',
36
+ 'influxdb': 'InfluxDB, Influx',
37
+ 'redis_hash': 'Redis, Redis Hash',
38
+
39
+ // HTTP/API
40
+ 'http_client': 'HTTP, REST API, REST',
41
+ 'http_server': 'HTTP, REST API, REST, Gateway',
42
+ 'webhook': 'Webhook, HTTP',
43
+
44
+ // File formats
45
+ 'unarchive': 'ZIP, TAR, GZIP, Archive, JSON, CSV',
46
+ 'archive': 'ZIP, TAR, GZIP, Archive',
47
+ 'lines': 'Text Files, Plain Text, Log Files',
48
+ 'csv': 'CSV, Comma-Separated Values',
49
+
50
+ // Cloud providers (generic patterns will catch aws_*, gcp_*, azure_*)
51
+ 'gcp_pubsub': 'Google Cloud Pub/Sub, GCP Pub/Sub, Google Pub/Sub',
52
+ 'gcp_bigquery': 'Google BigQuery, GCP BigQuery, BigQuery',
53
+ 'gcp_cloud_storage': 'Google Cloud Storage, GCS, GCP Cloud Storage',
54
+ 'azure_blob_storage': 'Azure Blob Storage, Microsoft Azure Storage',
55
+ 'azure_queue_storage': 'Azure Queue Storage, Microsoft Azure Queue',
56
+ 'azure_table_storage': 'Azure Table Storage, Microsoft Azure Table',
57
+ };
58
+
59
+ // Pattern-based commercial names (for connectors not in explicit mapping)
60
+ function getCommercialNamesFromPattern(connectorName) {
61
+ const names = [];
62
+
63
+ // AWS pattern
64
+ if (connectorName.startsWith('aws_')) {
65
+ names.push('Amazon');
66
+ names.push('AWS');
67
+ const serviceName = connectorName.replace('aws_', '').replace(/_/g, ' ');
68
+ names.push(serviceName.split(' ').map(w => w.charAt(0).toUpperCase() + w.slice(1)).join(' '));
69
+ }
70
+
71
+ // GCP pattern
72
+ if (connectorName.startsWith('gcp_')) {
73
+ names.push('Google Cloud');
74
+ names.push('GCP');
75
+ }
76
+
77
+ // Azure pattern
78
+ if (connectorName.startsWith('azure_')) {
79
+ names.push('Microsoft Azure');
80
+ names.push('Azure');
81
+ }
82
+
83
+ // SQL databases
84
+ if (connectorName.startsWith('sql_')) {
85
+ names.push('SQL');
86
+ names.push('PostgreSQL');
87
+ names.push('MySQL');
88
+ names.push('Microsoft SQL Server');
89
+ names.push('ClickHouse');
90
+ names.push('Trino');
91
+ }
92
+
93
+ return names;
94
+ }
95
+
96
+ function getCommercialNames(connectorName) {
97
+ // Check explicit mapping first
98
+ if (commercialNameMappings[connectorName]) {
99
+ return commercialNameMappings[connectorName];
100
+ }
101
+
102
+ // Try pattern matching
103
+ const patternNames = getCommercialNamesFromPattern(connectorName);
104
+ if (patternNames.length > 0) {
105
+ return patternNames.join(', ');
106
+ }
107
+
108
+ return null;
109
+ }
110
+
111
+ function addCommercialNamesToFile(filePath) {
112
+ const content = fs.readFileSync(filePath, 'utf8');
113
+ let lines = content.split('\n');
114
+
115
+ // Extract connector name from file path
116
+ const connectorName = path.basename(filePath, '.adoc');
117
+
118
+ // Remove existing page-commercial-names if present (we'll re-add in correct location)
119
+ lines = lines.filter(line => !line.includes(':page-commercial-names:'));
120
+
121
+ // Get commercial names
122
+ const commercialNames = getCommercialNames(connectorName);
123
+ if (!commercialNames) {
124
+ return { status: 'skip', reason: 'no commercial names found' };
125
+ }
126
+
127
+ // Find the position to insert (after single-source tag if present, otherwise after title)
128
+ let insertIndex = -1;
129
+ let titleIndex = -1;
130
+
131
+ // First find the title
132
+ for (let i = 0; i < lines.length; i++) {
133
+ if (lines[i].startsWith('= ')) {
134
+ titleIndex = i;
135
+ break;
136
+ }
137
+ }
138
+
139
+ if (titleIndex === -1) {
140
+ return { status: 'error', reason: 'could not find title' };
141
+ }
142
+
143
+ // Look for single-source tag after the title (with or without space after //)
144
+ let foundSingleSource = false;
145
+ for (let i = titleIndex + 1; i < Math.min(titleIndex + 10, lines.length); i++) {
146
+ if (lines[i].includes('tag::single-source[]')) {
147
+ insertIndex = i + 1;
148
+ foundSingleSource = true;
149
+ break;
150
+ }
151
+ }
152
+
153
+ // If no single-source tag, insert after title
154
+ if (!foundSingleSource) {
155
+ insertIndex = titleIndex + 1;
156
+ // Skip any existing page attributes
157
+ while (insertIndex < lines.length && lines[insertIndex].startsWith(':')) {
158
+ insertIndex++;
159
+ }
160
+ }
161
+
162
+ if (insertIndex === -1) {
163
+ return { status: 'error', reason: 'could not find title' };
164
+ }
165
+
166
+ // Insert the attribute
167
+ lines.splice(insertIndex, 0, `:page-commercial-names: ${commercialNames}`);
168
+
169
+ // Write back
170
+ fs.writeFileSync(filePath, lines.join('\n'), 'utf8');
171
+
172
+ return { status: 'added', commercialNames };
173
+ }
174
+
175
+ // Main execution
176
+ const basePath = process.argv[2] || '/Users/jakecahill/Documents/rp-connect-docs';
177
+ const pattern = `${basePath}/modules/components/pages/{inputs,outputs,processors}/*.adoc`;
178
+
179
+ console.log(`Finding connector files in: ${pattern}`);
180
+ const files = glob.sync(pattern).filter(f => !f.endsWith('about.adoc'));
181
+
182
+ console.log(`Found ${files.length} connector files\n`);
183
+
184
+ let added = 0;
185
+ let skipped = 0;
186
+ let errors = 0;
187
+
188
+ files.forEach(file => {
189
+ const connectorName = path.basename(file, '.adoc');
190
+ const result = addCommercialNamesToFile(file);
191
+
192
+ if (result.status === 'added') {
193
+ console.log(`✅ ${connectorName}: ${result.commercialNames}`);
194
+ added++;
195
+ } else if (result.status === 'skip') {
196
+ skipped++;
197
+ } else if (result.status === 'error') {
198
+ console.error(`❌ ${connectorName}: ${result.reason}`);
199
+ errors++;
200
+ }
201
+ });
202
+
203
+ console.log(`\n📊 Summary:`);
204
+ console.log(` ✅ Added: ${added}`);
205
+ console.log(` ⏭️ Skipped: ${skipped}`);
206
+ console.log(` ❌ Errors: ${errors}`);
207
+ console.log(` 📝 Total: ${files.length}`);
@@ -274,7 +274,10 @@ IMPORTANT: This documentation is auto-generated. Do not edit manually. Run \`npm
274
274
  'get-console-version',
275
275
  'link-readme',
276
276
  'fetch',
277
- 'setup-mcp'
277
+ 'setup-mcp',
278
+ 'validate-mcp',
279
+ 'preview-prompt',
280
+ 'mcp-version'
278
281
  ];
279
282
 
280
283
  topLevelCommands.forEach(cmd => {
@@ -300,7 +303,8 @@ IMPORTANT: This documentation is auto-generated. Do not edit manually. Run \`npm
300
303
  'helm-spec',
301
304
  'cloud-regions',
302
305
  'crd-spec',
303
- 'bundle-openapi'
306
+ 'bundle-openapi',
307
+ 'update-connect-version'
304
308
  ];
305
309
 
306
310
  generateSubcommands.forEach(subcmd => {
@@ -50,6 +50,11 @@ module.exports = async function getConsoleVersion({ beta = false, fromAntora = f
50
50
  ? (data.latestBetaRelease || data.latestStableRelease)
51
51
  : data.latestStableRelease;
52
52
 
53
+ if (!version) {
54
+ console.error('Could not determine Console version');
55
+ process.exit(1);
56
+ }
57
+
53
58
  console.log(`CONSOLE_VERSION=${version}`);
54
59
  console.log(`CONSOLE_DOCKER_REPO=${CONSOLE_DOCKER_REPO}`);
55
60
  };
@@ -46,6 +46,11 @@ module.exports = async function getRedpandaVersion({ beta = false, fromAntora =
46
46
  const rc = data.latestRcRelease;
47
47
  const version = useBeta && rc ? rc.version : stableVersion;
48
48
 
49
+ if (!version) {
50
+ console.error('Could not determine Redpanda version');
51
+ process.exit(1);
52
+ }
53
+
49
54
  // Determine the Docker repository
50
55
  const dockerRepo = (useBeta && rc) ? 'redpanda-unstable' : 'redpanda';
51
56
 
@@ -296,7 +296,7 @@ function generateConsoleReport(report, oldVersion, newVersion) {
296
296
  }
297
297
 
298
298
  if (report.emptyDescriptions.length > 0) {
299
- console.log(`\n⚠️ Properties with empty descriptions (${report.emptyDescriptions.length}):`);
299
+ console.log(`\nWarning: Properties with empty descriptions (${report.emptyDescriptions.length}):`);
300
300
  report.emptyDescriptions.forEach(prop => {
301
301
  console.log(` • ${prop.name} (${prop.type})`);
302
302
  });
@@ -362,7 +362,7 @@ function generateJsonReport(report, oldVersion, newVersion, outputPath) {
362
362
  */
363
363
  function comparePropertyFiles(oldFilePath, newFilePath, oldVersion, newVersion, outputDir, filename = 'property-changes.json') {
364
364
  try {
365
- console.log(`📊 Comparing property files:`);
365
+ console.log(`Comparing property files:`);
366
366
  console.log(` Old: ${oldFilePath}`);
367
367
  console.log(` New: ${newFilePath}`);
368
368
 
@@ -383,7 +383,7 @@ function comparePropertyFiles(oldFilePath, newFilePath, oldVersion, newVersion,
383
383
 
384
384
  return report;
385
385
  } catch (error) {
386
- console.error(`❌ Error comparing properties: ${error.message}`);
386
+ console.error(`Error: Error comparing properties: ${error.message}`);
387
387
  process.exit(1);
388
388
  }
389
389
  }
@@ -25,7 +25,7 @@ const helpers = require('./helpers');
25
25
  // Register helpers
26
26
  Object.entries(helpers).forEach(([name, fn]) => {
27
27
  if (typeof fn !== 'function') {
28
- console.error(`❌ Helper "${name}" is not a function`);
28
+ console.error(`Error: Helper "${name}" is not a function`);
29
29
  process.exit(1);
30
30
  }
31
31
  handlebars.registerHelper(name, fn);
@@ -96,9 +96,9 @@ function registerPartials() {
96
96
  }
97
97
  handlebars.registerPartial('deprecated-property', fs.readFileSync(deprecatedPropertyTemplatePath, 'utf8'));
98
98
 
99
- console.log(' Registered all partials');
99
+ console.log('Done: Registered all partials');
100
100
  } catch (error) {
101
- console.error(' Failed to register Handlebars templates:');
101
+ console.error('Error: Failed to register Handlebars templates:');
102
102
  console.error(` ${error.message}`);
103
103
  throw error;
104
104
  }
@@ -140,7 +140,7 @@ function generatePropertyPartials(properties, partialsDir, onRender) {
140
140
 
141
141
  // Skip if we've already processed this key
142
142
  if (processedKeys.has(key)) {
143
- console.warn(`⚠️ Duplicate key detected: ${key}`);
143
+ console.warn(`Warning: Duplicate key detected: ${key}`);
144
144
  return;
145
145
  }
146
146
  processedKeys.add(key);
@@ -164,7 +164,7 @@ function generatePropertyPartials(properties, partialsDir, onRender) {
164
164
  propertyGroups['object-storage'].push(prop);
165
165
  break;
166
166
  default:
167
- console.warn(`⚠️ Unknown config_scope: ${prop.config_scope} for ${prop.name}`);
167
+ console.warn(`Warning: Unknown config_scope: ${prop.config_scope} for ${prop.name}`);
168
168
  break;
169
169
  }
170
170
  });
@@ -185,11 +185,11 @@ function generatePropertyPartials(properties, partialsDir, onRender) {
185
185
  const content = pieces.join('\n');
186
186
  const filename = `${type}-properties.adoc`;
187
187
  fs.writeFileSync(path.join(propertiesPartialsDir, filename), AUTOGEN_NOTICE + content, 'utf8');
188
- console.log(`✅ Generated ${filename} (${props.length} properties)`);
188
+ console.log(`Done: Generated ${filename} (${props.length} properties)`);
189
189
  totalCount += props.length;
190
190
  });
191
191
 
192
- console.log(`✅ Done. ${totalCount} total properties.`);
192
+ console.log(`Done: Done. ${totalCount} total properties.`);
193
193
  return totalCount;
194
194
  }
195
195
 
@@ -223,7 +223,7 @@ function generateDeprecatedDocs(properties, outputDir) {
223
223
 
224
224
  fs.mkdirSync(path.dirname(outputPath), { recursive: true });
225
225
  fs.writeFileSync(outputPath, AUTOGEN_NOTICE + template(data), 'utf8');
226
- console.log(`✅ Generated ${outputPath}`);
226
+ console.log(`Done: Generated ${outputPath}`);
227
227
  return deprecatedProperties.length;
228
228
  }
229
229
 
@@ -253,7 +253,7 @@ function generateTopicPropertyMappings(properties, partialsDir) {
253
253
  fs.mkdirSync(propertiesPartialsDir, { recursive: true });
254
254
  const mappingsOut = path.join(propertiesPartialsDir, 'topic-property-mappings.adoc');
255
255
  fs.writeFileSync(mappingsOut, AUTOGEN_NOTICE + rendered, 'utf8');
256
- console.log(`✅ Generated ${mappingsOut}`);
256
+ console.log(`Done: Generated ${mappingsOut}`);
257
257
  return topicProperties.length;
258
258
  }
259
259
 
@@ -324,7 +324,7 @@ function generateAllDocs(inputFile, outputDir) {
324
324
  try {
325
325
  generateTopicPropertyMappings(properties, process.env.OUTPUT_PARTIALS_DIR);
326
326
  } catch (err) {
327
- console.error(`❌ Failed to generate topic-property-mappings.adoc: ${err.message}`);
327
+ console.error(`Error: Failed to generate topic-property-mappings.adoc: ${err.message}`);
328
328
  }
329
329
  } else {
330
330
  console.log('📄 Skipping partial generation (set GENERATE_PARTIALS=1 and OUTPUT_PARTIALS_DIR to enable)');
@@ -338,7 +338,7 @@ function generateAllDocs(inputFile, outputDir) {
338
338
  ? ((partialsCount / totalProperties) * 100).toFixed(2)
339
339
  : '0.00';
340
340
 
341
- console.log('\n📊 Summary:');
341
+ console.log('\nSummary:');
342
342
  console.log(` Total properties found: ${totalProperties}`);
343
343
  console.log(` Property partials generated: ${partialsCount} (${pctRendered}% of total)`);
344
344
  console.log(` Not documented: ${notRendered}`);
@@ -374,15 +374,15 @@ if (require.main === module) {
374
374
 
375
375
  const [inputFile, outputDir] = args;
376
376
  if (!fs.existsSync(inputFile)) {
377
- console.error(`❌ Input file not found: ${inputFile}`);
377
+ console.error(`Error: Input file not found: ${inputFile}`);
378
378
  process.exit(1);
379
379
  }
380
380
 
381
381
  try {
382
382
  generateAllDocs(inputFile, outputDir);
383
- console.log(' Documentation generation completed successfully');
383
+ console.log('Done: Documentation generation completed successfully');
384
384
  } catch (err) {
385
- console.error(`❌ Error: ${err.message}`);
385
+ console.error(`Error: ${err.message}`);
386
386
  process.exit(1);
387
387
  }
388
388
  }
@@ -0,0 +1,46 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Standalone CLI tool to generate PR summaries from property diff JSON files
5
+ *
6
+ * Usage:
7
+ * node generate-pr-summary.js <diff-json-file>
8
+ *
9
+ * Example:
10
+ * node generate-pr-summary.js ../../docs-data/redpanda-property-changes-v25.3.1-to-v25.3.3.json
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+ const { printPRSummary } = require('./pr-summary-formatter');
16
+
17
+ // CLI usage
18
+ if (require.main === module) {
19
+ const args = process.argv.slice(2);
20
+
21
+ if (args.length < 1) {
22
+ console.error('Usage: node generate-pr-summary.js <diff-json-file>');
23
+ console.error('');
24
+ console.error('Example:');
25
+ console.error(' node generate-pr-summary.js redpanda-property-changes-v25.3.1-to-v25.3.3.json');
26
+ console.error('');
27
+ console.error('This tool reads a property diff JSON file (generated by compare-properties.js)');
28
+ console.error('and outputs a GitHub PR-ready markdown summary.');
29
+ process.exit(1);
30
+ }
31
+
32
+ const diffFilePath = path.resolve(args[0]);
33
+
34
+ if (!fs.existsSync(diffFilePath)) {
35
+ console.error(`Error: File not found: ${diffFilePath}`);
36
+ process.exit(1);
37
+ }
38
+
39
+ try {
40
+ const diffData = JSON.parse(fs.readFileSync(diffFilePath, 'utf8'));
41
+ printPRSummary(diffData);
42
+ } catch (error) {
43
+ console.error(`Error: Error reading diff file: ${error.message}`);
44
+ process.exit(1);
45
+ }
46
+ }