A CLI for publishing standard.site documents to ATProto sequoia.pub
standard site lexicon cli publishing

feat: add option to disable publishing (text) content

authored by willow.sh and committed by tangled.org 594cd435 da42a8c8

+40 -10
+6
packages/cli/src/commands/init.ts
··· 98 message: "URL path prefix for posts:", 99 placeholder: "/posts, /blog, /articles, etc.", 100 }), 101 }, 102 { onCancel }, 103 ); ··· 341 pdsUrl, 342 frontmatter: frontmatterMapping, 343 bluesky: blueskyConfig, 344 }); 345 346 const configPath = path.join(process.cwd(), "sequoia.json");
··· 98 message: "URL path prefix for posts:", 99 placeholder: "/posts, /blog, /articles, etc.", 100 }), 101 + publishContent: () => 102 + confirm({ 103 + message: "Publish the post content on the standard.site document?", 104 + initialValue: true, 105 + }), 106 }, 107 { onCancel }, 108 ); ··· 346 pdsUrl, 347 frontmatter: frontmatterMapping, 348 bluesky: blueskyConfig, 349 + publishContent: siteConfig.publishContent, 350 }); 351 352 const configPath = path.join(process.cwd(), "sequoia.json");
+9
packages/cli/src/commands/update.ts
··· 162 stripDatePrefix: configUpdated.stripDatePrefix, 163 pathTemplate: configUpdated.pathTemplate, 164 textContentField: configUpdated.textContentField, 165 bluesky: configUpdated.bluesky, 166 }); 167 ··· 373 }), 374 ); 375 376 const textContentField = exitOnCancel( 377 await text({ 378 message: ··· 397 removeIndexFromSlug: removeIndexFromSlug || undefined, 398 stripDatePrefix: stripDatePrefix || undefined, 399 textContentField: textContentField || undefined, 400 }; 401 } 402
··· 162 stripDatePrefix: configUpdated.stripDatePrefix, 163 pathTemplate: configUpdated.pathTemplate, 164 textContentField: configUpdated.textContentField, 165 + publishContent: configUpdated.publishContent, 166 bluesky: configUpdated.bluesky, 167 }); 168 ··· 374 }), 375 ); 376 377 + const publishContent = exitOnCancel( 378 + await confirm({ 379 + message: "Publish the post content on the standard.site document?", 380 + initialValue: config.publishContent ?? true, 381 + }), 382 + ); 383 + 384 const textContentField = exitOnCancel( 385 await text({ 386 message: ··· 405 removeIndexFromSlug: removeIndexFromSlug || undefined, 406 stripDatePrefix: stripDatePrefix || undefined, 407 textContentField: textContentField || undefined, 408 + publishContent: publishContent ?? true, 409 }; 410 } 411
+11 -9
packages/cli/src/lib/atproto.ts
··· 252 ); 253 const publishDate = new Date(post.frontmatter.publishDate); 254 255 - // Determine textContent: use configured field from frontmatter, or fallback to markdown body 256 - let textContent: string; 257 if ( 258 config.textContentField && 259 post.rawFrontmatter?.[config.textContentField] 260 ) { 261 textContent = String(post.rawFrontmatter[config.textContentField]); 262 - } else { 263 textContent = stripMarkdownForText(post.content); 264 } 265 ··· 268 title: post.frontmatter.title, 269 site: config.publicationUri, 270 path: postPath, 271 - textContent: textContent.slice(0, 10000), 272 publishedAt: publishDate.toISOString(), 273 canonicalUrl: `${config.siteUrl}${postPath}`, 274 }; ··· 317 ); 318 const publishDate = new Date(post.frontmatter.publishDate); 319 320 - // Determine textContent: use configured field from frontmatter, or fallback to markdown body 321 - let textContent: string; 322 if ( 323 config.textContentField && 324 post.rawFrontmatter?.[config.textContentField] 325 ) { 326 textContent = String(post.rawFrontmatter[config.textContentField]); 327 - } else { 328 textContent = stripMarkdownForText(post.content); 329 } 330 ··· 342 title: post.frontmatter.title, 343 site: config.publicationUri, 344 path: postPath, 345 - textContent: textContent.slice(0, 10000), 346 publishedAt: publishDate.toISOString(), 347 canonicalUrl: `${config.siteUrl}${postPath}`, 348 }; ··· 384 title: string; 385 site: string; 386 path: string; 387 - textContent: string; 388 publishedAt: string; 389 canonicalUrl?: string; 390 description?: string;
··· 252 ); 253 const publishDate = new Date(post.frontmatter.publishDate); 254 255 + // Determine textContent (if enabled): use configured field from frontmatter, or fallback to markdown body 256 + let textContent: string | null = null; 257 if ( 258 + config.publishContent && 259 config.textContentField && 260 post.rawFrontmatter?.[config.textContentField] 261 ) { 262 textContent = String(post.rawFrontmatter[config.textContentField]); 263 + } else if (config.publishContent) { 264 textContent = stripMarkdownForText(post.content); 265 } 266 ··· 269 title: post.frontmatter.title, 270 site: config.publicationUri, 271 path: postPath, 272 + textContent: textContent?.slice(0, 10000), 273 publishedAt: publishDate.toISOString(), 274 canonicalUrl: `${config.siteUrl}${postPath}`, 275 }; ··· 318 ); 319 const publishDate = new Date(post.frontmatter.publishDate); 320 321 + // Determine textContent (if enabled): use configured field from frontmatter, or fallback to markdown body 322 + let textContent: string | null = null; 323 if ( 324 + config.publishContent && 325 config.textContentField && 326 post.rawFrontmatter?.[config.textContentField] 327 ) { 328 textContent = String(post.rawFrontmatter[config.textContentField]); 329 + } else if (config.publishContent) { 330 textContent = stripMarkdownForText(post.content); 331 } 332 ··· 344 title: post.frontmatter.title, 345 site: config.publicationUri, 346 path: postPath, 347 + textContent: textContent?.slice(0, 10000), 348 publishedAt: publishDate.toISOString(), 349 canonicalUrl: `${config.siteUrl}${postPath}`, 350 }; ··· 386 title: string; 387 site: string; 388 path: string; 389 + textContent?: string; 390 publishedAt: string; 391 canonicalUrl?: string; 392 description?: string;
+8 -1
packages/cli/src/lib/config.ts
··· 85 stripDatePrefix?: boolean; 86 pathTemplate?: string; 87 textContentField?: string; 88 bluesky?: BlueskyConfig; 89 }): string { 90 const config: Record<string, unknown> = { 91 - $schema: 'https://tangled.org/stevedylan.dev/sequoia/raw/main/sequoia.schema.json', 92 siteUrl: options.siteUrl, 93 contentDir: options.contentDir, 94 }; ··· 138 if (options.textContentField) { 139 config.textContentField = options.textContentField; 140 } 141 if (options.bluesky) { 142 config.bluesky = options.bluesky; 143 }
··· 85 stripDatePrefix?: boolean; 86 pathTemplate?: string; 87 textContentField?: string; 88 + publishContent?: boolean; 89 bluesky?: BlueskyConfig; 90 }): string { 91 const config: Record<string, unknown> = { 92 + $schema: 93 + "https://tangled.org/stevedylan.dev/sequoia/raw/main/sequoia.schema.json", 94 siteUrl: options.siteUrl, 95 contentDir: options.contentDir, 96 }; ··· 140 if (options.textContentField) { 141 config.textContentField = options.textContentField; 142 } 143 + 144 + if (options.publishContent) { 145 + config.publishContent = options.publishContent; 146 + } 147 + 148 if (options.bluesky) { 149 config.bluesky = options.bluesky; 150 }
+1
packages/cli/src/lib/types.ts
··· 41 stripDatePrefix?: boolean; // Remove YYYY-MM-DD- prefix from filenames (Jekyll-style, default: false) 42 pathTemplate?: string; // URL path template with tokens like {year}/{month}/{day}/{slug} (overrides pathPrefix + slug) 43 textContentField?: string; // Frontmatter field to use for textContent instead of markdown body 44 bluesky?: BlueskyConfig; // Optional Bluesky posting configuration 45 ui?: UIConfig; // Optional UI components configuration 46 }
··· 41 stripDatePrefix?: boolean; // Remove YYYY-MM-DD- prefix from filenames (Jekyll-style, default: false) 42 pathTemplate?: string; // URL path template with tokens like {year}/{month}/{day}/{slug} (overrides pathPrefix + slug) 43 textContentField?: string; // Frontmatter field to use for textContent instead of markdown body 44 + publishContent?: boolean; // Whether or not to publish the documents content on the standard.site document (default: true) 45 bluesky?: BlueskyConfig; // Optional Bluesky posting configuration 46 ui?: UIConfig; // Optional UI components configuration 47 }
+5
sequoia.schema.json
··· 116 "type": "string", 117 "description": "Frontmatter field to use for textContent instead of markdown body" 118 }, 119 "bluesky": { 120 "type": "object", 121 "additionalProperties": false,
··· 116 "type": "string", 117 "description": "Frontmatter field to use for textContent instead of markdown body" 118 }, 119 + "publishContent": { 120 + "type": "boolean", 121 + "description": "Whether or not to publish the documents content on the standard.site document", 122 + "default": true 123 + }, 124 "bluesky": { 125 "type": "object", 126 "additionalProperties": false,