comments.js
1 import { cli, Strategy } from '@jackwener/opencli/registry'; 2 import { EmptyResultError } from '@jackwener/opencli/errors'; 3 import { DOMAIN, SITE, gqlEscape, gqlRequest, parsePostId, stripHtml, } from './_helpers.js'; 4 cli({ 5 site: SITE, 6 name: 'comments', 7 description: 'Top comments on a post', 8 domain: DOMAIN, 9 strategy: Strategy.PUBLIC, 10 browser: false, 11 args: [ 12 { 13 name: 'url-or-id', 14 type: 'string', 15 required: true, 16 positional: true, 17 help: 'Post URL or LessWrong post ID', 18 }, 19 { name: 'limit', type: 'int', default: 5, help: 'Number of comments' }, 20 ], 21 columns: ['rank', 'score', 'author', 'text'], 22 func: async (_page, kwargs) => { 23 const postId = gqlEscape(parsePostId(String(kwargs['url-or-id']))); 24 const limit = Number(kwargs.limit ?? 5); 25 // Fetch post title and comments in parallel 26 const [postData, commentsData] = await Promise.all([ 27 gqlRequest(`query PostTitle { 28 post(input: {selector: {documentId: "${postId}"}}) { 29 result { _id title slug } 30 } 31 }`), 32 gqlRequest(`query Comments { 33 comments(input: {terms: {view: "postCommentsTop", postId: "${postId}", limit: ${limit}}}) { 34 results { _id user { displayName } baseScore htmlBody postedAt } 35 } 36 }`), 37 ]); 38 const post = postData?.post?.result; 39 if (!post?._id) { 40 throw new EmptyResultError('lesswrong comments', `Post "${postId}" not found`); 41 } 42 const comments = (commentsData?.comments?.results ?? []); 43 const rows = []; 44 // First row: post context 45 rows.push({ 46 rank: '', 47 score: '', 48 author: '', 49 text: `Comments on: ${post.title ?? 'Untitled'} (https://${DOMAIN}/posts/${post._id}/${post.slug})`, 50 }); 51 for (let i = 0; i < comments.length; i++) { 52 const item = comments[i]; 53 const user = item.user; 54 const raw = stripHtml(item.htmlBody ?? ''); 55 rows.push({ 56 rank: i + 1, 57 score: item.baseScore ?? 0, 58 author: user?.displayName ?? 'Unknown', 59 text: raw.length > 500 ? `${raw.slice(0, 500)}...` : raw, 60 }); 61 } 62 return rows; 63 }, 64 });