@brianlovin/hn-cli 0.1.7 → 0.1.8

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 (3) hide show
  1. package/README.md +10 -10
  2. package/dist/cli.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -2,31 +2,31 @@
2
2
 
3
3
  A terminal UI for browsing Hacker News, modeled after the HN reader on my [personal website](https://brianlovin.com/hn).
4
4
 
5
- ## Installation
5
+ ## Quick Start
6
6
 
7
7
  ```bash
8
- # Install Bun if you haven't already
9
- curl -fsSL https://bun.sh/install | bash
8
+ bunx @brianlovin/hn-cli
9
+ ```
10
10
 
11
- # Run directly with bunx
11
+ > Requires [Bun](https://bun.sh). Install with `curl -fsSL https://bun.sh/install | bash`
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ # Run directly (no install needed)
12
17
  bunx @brianlovin/hn-cli
13
18
 
14
19
  # Or install globally
15
20
  bun install -g @brianlovin/hn-cli
16
- hn-cli
21
+ hn
17
22
  ```
18
23
 
19
24
  ### From source
20
25
 
21
26
  ```bash
22
- # Clone the repository
23
27
  git clone https://github.com/brianlovin/hn-cli.git
24
28
  cd hn-cli
25
-
26
- # Install dependencies
27
29
  bun install
28
-
29
- # Run the app
30
30
  bun run start
31
31
  ```
32
32
 
package/dist/cli.js CHANGED
@@ -180,7 +180,7 @@ The user is reading this in a terminal app and wants to discuss it with you. Be
180
180
 
181
181
  ${g?`The original article URL is: ${g}`:""}`;try{if(this.chatProvider==="anthropic")await this.streamAnthropicResponse(A,E,q);else await this.streamOpenAIResponse(A,E,q)}catch(F){let K=F instanceof Error?F.message:"Unknown error",Z=this.chatProvider==="anthropic"?"Anthropic":"OpenAI";if(this.chatMessages[q])this.chatMessages[q].content=`Error: ${K}
182
182
 
183
- Check your ${Z} API key in ~/.config/hn-cli/config.json`,this.renderChatMessages()}this.isStreaming=!1}async streamAnthropicResponse(A,q,g){if(!this.anthropic){let K=zg("anthropic");this.anthropic=new Iq({apiKey:K})}let E=this.anthropic.messages.stream({model:X6("anthropic"),max_tokens:4096,system:q,messages:this.chatMessages.slice(0,-1).map((K)=>({role:K.role,content:K.content})).concat([{role:"user",content:A}])}),F="";E.on("text",(K)=>{if(F+=K,this.chatMessages[g])this.chatMessages[g].content=F,this.renderChatMessages()}),await E.finalMessage()}async streamOpenAIResponse(A,q,g){if(JA("[openai-stream] Starting stream..."),!this.openai){let Z=zg("openai");JA("[openai-stream] Initializing client, API key exists:",!!Z),this.openai=new e({apiKey:Z})}let E=X6("openai");JA("[openai-stream] Model:",E),JA("[openai-stream] Message count:",this.chatMessages.length);let F=await this.openai.chat.completions.create({model:E,max_completion_tokens:4096,stream:!0,messages:[{role:"system",content:q},...this.chatMessages.slice(0,-1).map((Z)=>({role:Z.role,content:Z.content})),{role:"user",content:A}]});JA("[openai-stream] Stream created, reading chunks...");let K="";for await(let Z of F){let j=Z.choices[0]?.delta?.content;if(j){if(K+=j,this.chatMessages[g])this.chatMessages[g].content=K,this.renderChatMessages()}}JA("[openai-stream] Stream complete, response length:",K.length)}createShortcutsBar(){let A=new s(this.ctx,{width:"100%",height:3,flexDirection:"row",alignItems:"center",paddingLeft:2,paddingRight:2,paddingBottom:1,backgroundColor:h.bg,borderStyle:"single",border:["top"],borderColor:h.border,gap:2});return[{key:"j/k",desc:"stories"},{key:"\u2318j/k",desc:"comments"},{key:"o",desc:"open"},{key:"c",desc:"chat"},{key:"q",desc:"quit"}].forEach(({key:g,desc:E})=>{let F=new s(this.ctx,{flexDirection:"row",gap:1}),K=new o(this.ctx,{content:g,fg:h.accent}),Z=new o(this.ctx,{content:E,fg:h.textDim});F.add(K),F.add(Z),A.add(F)}),A}setupKeyboardHandlers(){this.renderer.keyInput.on("keypress",(A)=>{if(A.name==="q"||A.ctrl&&A.name==="c"){this.callbacks.onExit?.();return}if(this.settingsMode){if(A.name==="escape"){if(this.settingsSection==="model")this.settingsSection="main",this.settingsSelectedIndex=0,this.renderSettings();else this.hideSettings();return}if(A.name==="j"||A.name==="down")this.navigateSettings(1);else if(A.name==="k"||A.name==="up")this.navigateSettings(-1);else if(A.name==="return"||A.name==="enter")this.selectSettingsItem();return}if(this.authSetupMode){if(A.name==="escape"){this.hideAuthSetup();return}if(this.authSetupStep==="provider"){if(A.name==="j"||A.name==="down")this.authSelectedProvider="openai",this.renderAuthSetup();else if(A.name==="k"||A.name==="up")this.authSelectedProvider="anthropic",this.renderAuthSetup();else if(A.name==="return"||A.name==="enter")this.authSetupStep="key",this.renderAuthSetup()}return}if(this.chatMode){if(A.name==="escape"){this.hideChatView();return}if(A.name===","||A.sequence===","){this.showSettings();return}if(this.suggestions.length>0&&this.chatInput&&!this.chatInput.plainText.trim()){if(A.name==="up"||A.name==="k"){this.navigateSuggestion(-1);return}else if(A.name==="down"||A.name==="j"){this.navigateSuggestion(1);return}}if((A.name==="return"||A.name==="enter")&&!A.shift){if(this.chatInput&&this.chatInput.plainText.trim()){this.sendChatMessage();return}if(this.selectedSuggestionIndex>=0&&this.suggestions.length>0){this.selectSuggestion();return}return}if(this.suggestions.length>0&&A.sequence&&A.sequence.length===1&&!A.ctrl&&!A.meta){let g=A.sequence.charCodeAt(0);if(g>=32&&g<=126)this.suggestions=[],this.selectedSuggestionIndex=-1,this.renderSuggestions()}if(A.name==="backspace"&&this.chatInput&&this.originalSuggestions.length>0)setTimeout(()=>{if(this.chatInput&&!this.chatInput.plainText.trim()&&this.suggestions.length===0)this.suggestions=[...this.originalSuggestions],this.selectedSuggestionIndex=this.suggestions.length-1,this.renderSuggestions()},10);return}let q=A.meta;if(A.name==="j"&&!q)this.navigateStory(1);else if(A.name==="k"&&!q)this.navigateStory(-1);else if(A.name==="j"&&q)this.navigateToNextComment();else if(A.name==="k"&&q)this.navigateToPreviousComment();else if(A.name==="o")this.openStoryUrl();else if(A.name==="c")this.openChat();else if(A.name==="r")this.refresh()})}async loadPosts(){this.startLoadingAnimation();try{this.posts=await YM(),this.stopLoadingAnimation(),this.renderStoryList(),this.renderEmptyDetail()}catch(A){this.stopLoadingAnimation(),JA("[ERROR]","Error loading posts:",A)}}renderStoryList(){for(let A of this.storyListScroll.getChildren())this.storyListScroll.remove(A.id);this.storyItems.clear(),this.posts.forEach((A,q)=>{let g=this.createStoryItem(A,q);this.storyItems.set(q,g),this.storyListScroll.add(g)})}createStoryItem(A,q){let g=q===this.selectedIndex,E=new s(this.ctx,{id:`story-${A.id}`,width:"100%",paddingTop:0,paddingBottom:0,backgroundColor:h.bg,flexDirection:"row",onMouseDown:()=>{this.selectStory(q)}}),F=new o(this.ctx,{id:`chevron-${A.id}`,content:g?"\u203A":" ",fg:g?h.accent:h.textVeryDim,width:2,paddingLeft:1});E.add(F);let K=new s(this.ctx,{id:`content-${A.id}`,flexGrow:1,flexDirection:"column",paddingRight:1});E.add(K);let Z=80,j=new o(this.ctx,{id:`title-${A.id}`,content:this.truncateText(A.title,Z),fg:g?h.accent:h.text});if(K.add(j),A.domain){let U=new o(this.ctx,{id:`domain-${A.id}`,content:A.domain,fg:h.textDim});K.add(U)}return E}async selectStory(A){if(A<0||A>=this.posts.length)return;if(this.renderer.isDestroyed)return;let q=this.selectedIndex;this.selectedIndex=A,this.rootCommentIndex=0,this.updateStoryItemStyle(q,!1),this.updateStoryItemStyle(A,!0);let g=this.posts[A];if(!g)return;try{let K=await GM(g.id);if(this.renderer.isDestroyed)return;if(K)this.selectedPost=K,this.renderDetail(K)}catch(K){JA("[ERROR]","Error loading post:",K)}if(this.renderer.isDestroyed)return;let F=Math.max(0,A*2-5);this.storyListScroll.scrollTop=F}updateStoryItemStyle(A,q){let g=this.storyItems.get(A);if(!g)return;if(!this.posts[A])return;let F=g.getChildren();if(F.length>=2){let K=F[0];if(K&&"content"in K)K.content=q?"\u203A":" ",K.fg=q?h.accent:h.textVeryDim;let j=F[1].getChildren();if(j.length>0){let U=j[0];if(U&&"content"in U)U.fg=q?h.accent:h.text}}}renderDetail(A){for(let F of this.detailHeader.getChildren())this.detailHeader.remove(F.id);for(let F of this.detailContent.getChildren())this.detailContent.remove(F.id);this.rootCommentBoxes=[];let q=new o(this.ctx,{content:A.title,fg:h.text,wrapMode:"word",flexShrink:0,maxHeight:2,onMouseDown:()=>this.openStoryUrl(),onMouseOver:()=>{q.fg=h.link},onMouseOut:()=>{q.fg=h.text}});if(this.detailHeader.add(q),A.domain){let F=new o(this.ctx,{content:A.domain,fg:h.textDim,flexShrink:0,onMouseDown:()=>this.openStoryUrl()});this.detailHeader.add(F)}if(A.content){let F=new s(this.ctx,{width:"100%",marginBottom:1}),K=new o(this.ctx,{content:this.stripHtml(A.content),fg:h.text,wrapMode:"word"});F.add(K),this.detailContent.add(F)}let g=new s(this.ctx,{width:"100%",flexDirection:"column"}),E=new o(this.ctx,{content:`${A.comments_count} comments`,fg:h.textDim});if(g.add(E),A.comments&&A.comments.length>0)A.comments.forEach((F,K)=>{let Z=this.renderComment(F,K);if(g.add(Z),F.level===0)this.rootCommentBoxes.push(Z)});else{let F=new o(this.ctx,{content:"No comments yet...",fg:h.textDim});g.add(F)}this.detailContent.add(g),this.detailScroll.scrollTop=0}renderEmptyDetail(){for(let q of this.detailHeader.getChildren())this.detailHeader.remove(q.id);for(let q of this.detailContent.getChildren())this.detailContent.remove(q.id);let A=new o(this.ctx,{content:"Select a story to view details",fg:h.textDim});this.detailHeader.add(A)}renderComment(A,q){let g=A.level===0,F={0:h.accent,1:h.commentL1,2:h.commentL2,3:h.commentL3}[A.level]??h.commentL3,K=new s(this.ctx,{id:`comment-wrapper-${A.id}`,width:"100%",marginTop:1,flexDirection:"row"});if(A.level>0){let U=new s(this.ctx,{width:A.level*2,flexShrink:0});K.add(U)}let Z=new s(this.ctx,{id:`comment-${A.id}`,flexGrow:1,flexShrink:1,paddingLeft:1,paddingRight:1,borderStyle:"single",border:["left"],borderColor:F,flexDirection:"column"}),j=new o(this.ctx,{content:A.user||"[deleted]",fg:g?h.accent:h.textDim});if(Z.add(j),A.content){let U=new o(this.ctx,{content:this.stripHtml(A.content),fg:h.text,wrapMode:"word"});Z.add(U)}else if(A.deleted){let U=new o(this.ctx,{content:"[deleted]",fg:h.textMuted});Z.add(U)}if(K.add(Z),A.comments&&A.comments.length>0){let U=new s(this.ctx,{width:"100%",flexDirection:"column"});A.comments.forEach((Y)=>{let M=this.renderComment(Y);U.add(M)});let O=new s(this.ctx,{width:"100%",flexDirection:"column"});return O.add(K),O.add(U),O}return K}navigateStory(A){if(this.posts.length===0)return;if(this.selectedIndex===-1){if(A>0)this.selectStory(0);else this.selectStory(this.posts.length-1);return}let q=this.selectedIndex+A;if(q>=0&&q<this.posts.length)this.selectStory(q)}navigateToNextComment(){if(!this.selectedPost)return;if(this.rootCommentBoxes.length===0)return;let A=this.rootCommentBoxes.length-1;if(this.rootCommentIndex<A)this.rootCommentIndex++,this.scrollToRootComment(this.rootCommentIndex)}navigateToPreviousComment(){if(!this.selectedPost)return;if(this.rootCommentBoxes.length===0)return;if(this.rootCommentIndex>0)this.rootCommentIndex--,this.scrollToRootComment(this.rootCommentIndex)}scrollToRootComment(A){if(A<0||A>=this.rootCommentBoxes.length)return;let q=this.rootCommentBoxes[A];if(!q)return;let g=this.detailScroll.content,E=q.y-g.y;this.detailScroll.scrollTop=Math.max(0,E-1)}openStoryUrl(){if(!this.selectedPost)return;let A=this.selectedPost.url||`https://news.ycombinator.com/item?id=${this.selectedPost.id}`;this.callbacks.onOpenUrl?.(A)}openOnHN(){if(!this.selectedPost)return;let A=`${vH}/${this.selectedPost.id}`;this.callbacks.onOpenUrl?.(A)}openChat(){if(!this.selectedPost)return;let A=JM();if(A)this.chatProvider=A,this.showChatView();else this.showAuthSetup()}showAuthSetup(){this.authSetupMode=!0,this.authSetupStep="provider",this.authSelectedProvider="anthropic",this.detailPanel.remove(this.detailHeader.id),this.detailPanel.remove(this.detailScroll.id),this.detailPanel.remove(this.shortcutsBar.id),this.renderAuthSetup()}hideAuthSetup(){this.authSetupMode=!1;for(let A of this.detailPanel.getChildren())this.detailPanel.remove(A.id);if(this.detailPanel.add(this.detailHeader),this.detailPanel.add(this.detailScroll),this.detailPanel.add(this.shortcutsBar),this.selectedPost)this.renderDetail(this.selectedPost)}renderAuthSetup(){for(let g of this.detailPanel.getChildren())this.detailPanel.remove(g.id);let A=new s(this.ctx,{width:"100%",height:"100%",flexDirection:"column",paddingLeft:2,paddingRight:2,paddingTop:2,backgroundColor:h.bg}),q=new o(this.ctx,{content:"Set up AI Chat",fg:h.accent});if(A.add(q),A.add(new s(this.ctx,{height:1})),this.authSetupStep==="provider"){let g=new o(this.ctx,{content:"Choose your AI provider:",fg:h.text});A.add(g),A.add(new s(this.ctx,{height:1}));let E=new s(this.ctx,{flexDirection:"row",gap:1}),F=new o(this.ctx,{content:this.authSelectedProvider==="anthropic"?"\u25CF":"\u25CB",fg:this.authSelectedProvider==="anthropic"?h.accent:h.textDim}),K=new o(this.ctx,{content:"Anthropic",fg:this.authSelectedProvider==="anthropic"?h.accent:h.text});E.add(F),E.add(K),A.add(E);let Z=new s(this.ctx,{flexDirection:"row",gap:1}),j=new o(this.ctx,{content:this.authSelectedProvider==="openai"?"\u25CF":"\u25CB",fg:this.authSelectedProvider==="openai"?h.accent:h.textDim}),U=new o(this.ctx,{content:"OpenAI",fg:this.authSelectedProvider==="openai"?h.accent:h.text});Z.add(j),Z.add(U),A.add(Z),A.add(new s(this.ctx,{height:2}));let O=new o(this.ctx,{content:"\u2191/\u2193 to select, Enter to continue, Esc to cancel",fg:h.textDim});A.add(O)}else if(this.authSetupStep==="key"){let g=this.authSelectedProvider==="anthropic"?"Anthropic":"OpenAI",E=new o(this.ctx,{content:`Enter your ${g} API key:`,fg:h.text});A.add(E),A.add(new s(this.ctx,{height:1}));let F=new s(this.ctx,{width:"100%",flexDirection:"row",gap:1}),K=new o(this.ctx,{content:"\u203A",fg:h.accent});F.add(K),this.authKeyInput=new ZZ(this.ctx,{width:"100%",flexGrow:1,placeholder:this.authSelectedProvider==="anthropic"?"sk-ant-...":"sk-...",backgroundColor:h.bg}),this.authKeyInput.on("enter",()=>{this.saveApiKey()}),F.add(this.authKeyInput),A.add(F),A.add(new s(this.ctx,{height:2}));let Z=new o(this.ctx,{content:"Your key is stored locally at ~/.config/hn-cli/config.json",fg:h.textDim,wrapMode:"word"});A.add(Z),A.add(new s(this.ctx,{height:1}));let j=new o(this.ctx,{content:"This app is open source: github.com/brianlovin/hn-cli",fg:h.textDim,wrapMode:"word"});A.add(j),A.add(new s(this.ctx,{height:2}));let U=new o(this.ctx,{content:"Enter to save, Esc to cancel",fg:h.textDim});A.add(U),setTimeout(()=>{if(this.authKeyInput)this.authKeyInput.focus(),this.authKeyInput.value=""},50)}this.detailPanel.add(A)}saveApiKey(){if(!this.authKeyInput)return;let A=this.authKeyInput.value.trim();if(!A)return;let q=hg();if(q.provider=this.authSelectedProvider,this.authSelectedProvider==="anthropic")q.anthropicApiKey=A;else q.openaiApiKey=A;TK(q),this.hideAuthSetup(),this.chatProvider=this.authSelectedProvider,this.showChatView()}showSettings(){this.settingsMode=!0,this.settingsSection="main",this.settingsSelectedIndex=0;for(let A of this.detailPanel.getChildren())this.detailPanel.remove(A.id);this.renderSettings()}hideSettings(){this.settingsMode=!1;for(let A of this.detailPanel.getChildren())this.detailPanel.remove(A.id);if(this.createChatPanel(),this.chatPanel)for(let A of this.chatPanel.getChildren())this.detailPanel.add(A);if(this.chatInput)this.chatInput.focus(),this.chatInput.clear();this.renderSuggestions()}getSettingsItems(){let A=!!zg("anthropic"),q=!!zg("openai"),g=[];g.push({label:`Provider: ${this.chatProvider==="anthropic"?"Anthropic":"OpenAI"}`,action:"switch_provider",enabled:A&&q});let E=X6(this.chatProvider),K=(this.chatProvider==="anthropic"?NK:xK).find((Z)=>Z.id===E)?.name||E;if(g.push({label:`Model: ${K}`,action:"change_model",enabled:!0}),!A)g.push({label:"Add Anthropic API key",action:"add_anthropic",enabled:!0});if(!q)g.push({label:"Add OpenAI API key",action:"add_openai",enabled:!0});if(A||q)g.push({label:"Clear all API keys",action:"clear_keys",enabled:!0});return g}renderSettings(){for(let g of this.detailPanel.getChildren())this.detailPanel.remove(g.id);let A=new s(this.ctx,{width:"100%",height:"100%",flexDirection:"column",paddingLeft:2,paddingRight:2,paddingTop:2,backgroundColor:h.bg}),q=new o(this.ctx,{content:"Settings",fg:h.accent});if(A.add(q),A.add(new s(this.ctx,{height:1})),this.settingsSection==="main"){this.getSettingsItems().forEach((F,K)=>{let Z=K===this.settingsSelectedIndex,j=new s(this.ctx,{flexDirection:"row",gap:1}),U=new o(this.ctx,{content:Z?"\u203A":" ",fg:h.accent});j.add(U);let O=new o(this.ctx,{content:F.label,fg:Z?h.accent:F.enabled?h.text:h.textDim});j.add(O),A.add(j)}),A.add(new s(this.ctx,{height:2}));let E=new o(this.ctx,{content:"\u2191/\u2193 navigate Enter select Esc back",fg:h.textDim});A.add(E)}else if(this.settingsSection==="model"){let g=this.settingsModelProvider==="anthropic"?NK:xK,E=X6(this.settingsModelProvider),F=new o(this.ctx,{content:`Select ${this.settingsModelProvider==="anthropic"?"Anthropic":"OpenAI"} model:`,fg:h.text});A.add(F),A.add(new s(this.ctx,{height:1})),g.forEach((Z,j)=>{let U=j===this.settingsSelectedIndex,O=Z.id===E,Y=new s(this.ctx,{flexDirection:"row",gap:1}),M=new o(this.ctx,{content:U?"\u203A":" ",fg:h.accent});Y.add(M);let J=new o(this.ctx,{content:O?"\u25CF":"\u25CB",fg:O?h.accent:h.textDim});Y.add(J);let $=new o(this.ctx,{content:Z.name,fg:U?h.accent:h.text});Y.add($),A.add(Y)}),A.add(new s(this.ctx,{height:2}));let K=new o(this.ctx,{content:"\u2191/\u2193 navigate Enter select Esc back",fg:h.textDim});A.add(K)}this.detailPanel.add(A)}navigateSettings(A){let q;if(this.settingsSection==="main")q=this.getSettingsItems().length-1;else q=(this.settingsModelProvider==="anthropic"?NK:xK).length-1;this.settingsSelectedIndex=Math.max(0,Math.min(q,this.settingsSelectedIndex+A)),this.renderSettings()}selectSettingsItem(){if(this.settingsSection==="main"){let q=this.getSettingsItems()[this.settingsSelectedIndex];if(!q||!q.enabled)return;switch(q.action){case"switch_provider":this.chatProvider=this.chatProvider==="anthropic"?"openai":"anthropic";let g=hg();g.provider=this.chatProvider,TK(g),this.anthropic=null,this.openai=null,this.renderSettings();break;case"change_model":this.settingsSection="model",this.settingsModelProvider=this.chatProvider,this.settingsSelectedIndex=0,this.renderSettings();break;case"add_anthropic":this.hideSettings(),this.authSelectedProvider="anthropic",this.authSetupStep="key",this.authSetupMode=!0,this.chatMode=!1,this.renderAuthSetup();break;case"add_openai":this.hideSettings(),this.authSelectedProvider="openai",this.authSetupStep="key",this.authSetupMode=!0,this.chatMode=!1,this.renderAuthSetup();break;case"clear_keys":_M(),this.anthropic=null,this.openai=null,this.hideSettings(),this.hideChatView();break}}else if(this.settingsSection==="model"){let q=(this.settingsModelProvider==="anthropic"?NK:xK)[this.settingsSelectedIndex];if(q){if(MM(this.settingsModelProvider,q.id),this.settingsModelProvider==="anthropic")this.anthropic=null;else this.openai=null;this.settingsSection="main",this.settingsSelectedIndex=1,this.renderSettings()}}}navigateSuggestion(A){if(this.suggestions.length===0)return;let q=this.selectedSuggestionIndex+A;this.selectedSuggestionIndex=Math.max(0,Math.min(this.suggestions.length-1,q)),this.renderSuggestions()}selectSuggestion(){if(this.selectedSuggestionIndex<0||this.selectedSuggestionIndex>=this.suggestions.length)return;let A=this.suggestions[this.selectedSuggestionIndex];if(!A)return;if(this.chatInput)this.chatInput.clear(),this.chatInput.insertText(A);this.suggestions=[],this.selectedSuggestionIndex=-1,this.renderSuggestions(),this.sendChatMessage()}renderSuggestions(){if(!this.suggestionsContainer)return;for(let A of this.suggestionsContainer.getChildren())this.suggestionsContainer.remove(A.id);if(this.suggestionsLoading){let A=new o(this.ctx,{id:"suggestions-loading",content:`${H6.LOADING_CHARS[this.loadingFrame]??"\u280B"} Generating suggestions...`,fg:h.textDim});this.suggestionsContainer.add(A);return}if(this.suggestions.length===0)return;for(let A=0;A<this.suggestions.length;A++){let q=this.suggestions[A];if(!q)continue;let g=A===this.selectedSuggestionIndex,E=new s(this.ctx,{id:`suggestion-row-${A}`,width:"100%",flexDirection:"row",backgroundColor:h.bg}),F=new o(this.ctx,{id:`suggestion-indicator-${A}`,content:g?"\u203A ":" ",fg:h.accent,width:2});E.add(F);let K=new o(this.ctx,{id:`suggestion-text-${A}`,content:q,fg:g?h.accent:h.textDim});E.add(K),this.suggestionsContainer.add(E)}}async generateSuggestions(){if(!this.selectedPost||this.suggestionsGenerated)return;JA("[suggestions] Starting generation..."),JA("[suggestions] Provider:",this.chatProvider),this.suggestionsGenerated=!0,this.suggestionsLoading=!0;let A=setInterval(()=>{if(!this.renderer.isDestroyed&&this.suggestionsLoading)this.loadingFrame=(this.loadingFrame+1)%H6.LOADING_CHARS.length,this.renderSuggestions()},80),q=this.selectedPost,g=q.comments?.slice(0,3).map((F)=>`${F.user}: ${this.stripHtml(F.content||"").slice(0,100)}...`).join(`
183
+ Check your ${Z} API key in ~/.config/hn-cli/config.json`,this.renderChatMessages()}this.isStreaming=!1}async streamAnthropicResponse(A,q,g){if(!this.anthropic){let K=zg("anthropic");this.anthropic=new Iq({apiKey:K})}let E=this.anthropic.messages.stream({model:X6("anthropic"),max_tokens:4096,system:q,messages:this.chatMessages.slice(0,-1).map((K)=>({role:K.role,content:K.content})).concat([{role:"user",content:A}])}),F="";E.on("text",(K)=>{if(F+=K,this.chatMessages[g])this.chatMessages[g].content=F,this.renderChatMessages()}),await E.finalMessage()}async streamOpenAIResponse(A,q,g){if(JA("[openai-stream] Starting stream..."),!this.openai){let Z=zg("openai");JA("[openai-stream] Initializing client, API key exists:",!!Z),this.openai=new e({apiKey:Z})}let E=X6("openai");JA("[openai-stream] Model:",E),JA("[openai-stream] Message count:",this.chatMessages.length);let F=await this.openai.chat.completions.create({model:E,max_completion_tokens:4096,stream:!0,messages:[{role:"system",content:q},...this.chatMessages.slice(0,-1).map((Z)=>({role:Z.role,content:Z.content})),{role:"user",content:A}]});JA("[openai-stream] Stream created, reading chunks...");let K="";for await(let Z of F){let j=Z.choices[0]?.delta?.content;if(j){if(K+=j,this.chatMessages[g])this.chatMessages[g].content=K,this.renderChatMessages()}}JA("[openai-stream] Stream complete, response length:",K.length)}createShortcutsBar(){let A=new s(this.ctx,{width:"100%",height:3,flexDirection:"row",alignItems:"center",paddingLeft:2,paddingRight:2,paddingBottom:1,backgroundColor:h.bg,borderStyle:"single",border:["top"],borderColor:h.border,gap:2});return[{key:"j/k",desc:"stories"},{key:"\u2318j/k",desc:"comments"},{key:"o",desc:"open"},{key:"c",desc:"chat"},{key:"q",desc:"quit"}].forEach(({key:g,desc:E})=>{let F=new s(this.ctx,{flexDirection:"row",gap:1}),K=new o(this.ctx,{content:g,fg:h.accent}),Z=new o(this.ctx,{content:E,fg:h.textDim});F.add(K),F.add(Z),A.add(F)}),A}setupKeyboardHandlers(){this.renderer.keyInput.on("keypress",(A)=>{if(A.name==="q"||A.ctrl&&A.name==="c"){this.callbacks.onExit?.();return}if(this.settingsMode){if(A.name==="escape"){if(this.settingsSection==="model")this.settingsSection="main",this.settingsSelectedIndex=0,this.renderSettings();else this.hideSettings();return}if(A.name==="j"||A.name==="down")this.navigateSettings(1);else if(A.name==="k"||A.name==="up")this.navigateSettings(-1);else if(A.name==="return"||A.name==="enter")this.selectSettingsItem();return}if(this.authSetupMode){if(A.name==="escape"){this.hideAuthSetup();return}if(this.authSetupStep==="provider"){if(A.name==="j"||A.name==="down")this.authSelectedProvider="openai",this.renderAuthSetup();else if(A.name==="k"||A.name==="up")this.authSelectedProvider="anthropic",this.renderAuthSetup();else if(A.name==="return"||A.name==="enter")this.authSetupStep="key",this.renderAuthSetup()}return}if(this.chatMode){if(A.name==="escape"){this.hideChatView();return}if(A.name===","||A.sequence===","){this.showSettings();return}if(this.suggestions.length>0&&this.chatInput&&!this.chatInput.plainText.trim()){if(A.name==="up"||A.name==="k"){this.navigateSuggestion(-1);return}else if(A.name==="down"||A.name==="j"){this.navigateSuggestion(1);return}}if((A.name==="return"||A.name==="enter")&&!A.shift){if(this.chatInput&&this.chatInput.plainText.trim()){this.sendChatMessage();return}if(this.selectedSuggestionIndex>=0&&this.suggestions.length>0){this.selectSuggestion();return}return}if(this.suggestions.length>0&&A.sequence&&A.sequence.length===1&&!A.ctrl&&!A.meta){let g=A.sequence.charCodeAt(0);if(g>=32&&g<=126)this.suggestions=[],this.selectedSuggestionIndex=-1,this.renderSuggestions()}if(A.name==="backspace"&&this.chatInput&&this.originalSuggestions.length>0)setTimeout(()=>{if(this.chatInput&&!this.chatInput.plainText.trim()&&this.suggestions.length===0)this.suggestions=[...this.originalSuggestions],this.selectedSuggestionIndex=this.suggestions.length-1,this.renderSuggestions()},10);return}let q=A.super;if(A.name==="j"&&!q)this.navigateStory(1);else if(A.name==="k"&&!q)this.navigateStory(-1);else if(A.name==="j"&&q)this.navigateToNextComment();else if(A.name==="k"&&q)this.navigateToPreviousComment();else if(A.name==="o")this.openStoryUrl();else if(A.name==="c")this.openChat();else if(A.name==="r")this.refresh()})}async loadPosts(){this.startLoadingAnimation();try{this.posts=await YM(),this.stopLoadingAnimation(),this.renderStoryList(),this.renderEmptyDetail()}catch(A){this.stopLoadingAnimation(),JA("[ERROR]","Error loading posts:",A)}}renderStoryList(){for(let A of this.storyListScroll.getChildren())this.storyListScroll.remove(A.id);this.storyItems.clear(),this.posts.forEach((A,q)=>{let g=this.createStoryItem(A,q);this.storyItems.set(q,g),this.storyListScroll.add(g)})}createStoryItem(A,q){let g=q===this.selectedIndex,E=new s(this.ctx,{id:`story-${A.id}`,width:"100%",paddingTop:0,paddingBottom:0,backgroundColor:h.bg,flexDirection:"row",onMouseDown:()=>{this.selectStory(q)}}),F=new o(this.ctx,{id:`chevron-${A.id}`,content:g?"\u203A":" ",fg:g?h.accent:h.textVeryDim,width:2,paddingLeft:1});E.add(F);let K=new s(this.ctx,{id:`content-${A.id}`,flexGrow:1,flexDirection:"column",paddingRight:2});E.add(K);let Z=80,j=new o(this.ctx,{id:`title-${A.id}`,content:this.truncateText(A.title,Z),fg:g?h.accent:h.text,maxHeight:2});if(K.add(j),A.domain){let U=new o(this.ctx,{id:`domain-${A.id}`,content:A.domain,fg:h.textDim});K.add(U)}return E}async selectStory(A){if(A<0||A>=this.posts.length)return;if(this.renderer.isDestroyed)return;let q=this.selectedIndex;this.selectedIndex=A,this.rootCommentIndex=0,this.updateStoryItemStyle(q,!1),this.updateStoryItemStyle(A,!0);let g=this.posts[A];if(!g)return;try{let U=await GM(g.id);if(this.renderer.isDestroyed)return;if(U)this.selectedPost=U,this.renderDetail(U)}catch(U){JA("[ERROR]","Error loading post:",U)}if(this.renderer.isDestroyed)return;let E=2,F=A*E,K=F+E,Z=this.storyListScroll.height,j=this.storyListScroll.scrollTop;if(F<j)this.storyListScroll.scrollTop=F;else if(K>j+Z)this.storyListScroll.scrollTop=K-Z}updateStoryItemStyle(A,q){let g=this.storyItems.get(A);if(!g)return;if(!this.posts[A])return;let F=g.getChildren();if(F.length>=2){let K=F[0];if(K&&"content"in K)K.content=q?"\u203A":" ",K.fg=q?h.accent:h.textVeryDim;let j=F[1].getChildren();if(j.length>0){let U=j[0];if(U&&"content"in U)U.fg=q?h.accent:h.text}}}renderDetail(A){for(let F of this.detailHeader.getChildren())this.detailHeader.remove(F.id);for(let F of this.detailContent.getChildren())this.detailContent.remove(F.id);this.rootCommentBoxes=[];let q=new o(this.ctx,{content:A.title,fg:h.text,wrapMode:"word",flexShrink:0,maxHeight:2,onMouseDown:()=>this.openStoryUrl(),onMouseOver:()=>{q.fg=h.link},onMouseOut:()=>{q.fg=h.text}});if(this.detailHeader.add(q),A.domain){let F=new o(this.ctx,{content:A.domain,fg:h.textDim,flexShrink:0,maxHeight:1,onMouseDown:()=>this.openStoryUrl()});this.detailHeader.add(F)}if(A.content){let F=new s(this.ctx,{width:"100%",marginBottom:1}),K=new o(this.ctx,{content:this.stripHtml(A.content),fg:h.text,wrapMode:"word"});F.add(K),this.detailContent.add(F)}let g=new s(this.ctx,{width:"100%",flexDirection:"column"}),E=new o(this.ctx,{content:`${A.comments_count} comments`,fg:h.textDim});if(g.add(E),A.comments&&A.comments.length>0)A.comments.forEach((F,K)=>{let Z=this.renderComment(F,K);if(g.add(Z),F.level===0)this.rootCommentBoxes.push(Z)});else{let F=new o(this.ctx,{content:"No comments yet...",fg:h.textDim});g.add(F)}this.detailContent.add(g),this.detailScroll.scrollTop=0}renderEmptyDetail(){for(let q of this.detailHeader.getChildren())this.detailHeader.remove(q.id);for(let q of this.detailContent.getChildren())this.detailContent.remove(q.id);let A=new o(this.ctx,{content:"Select a story to view details",fg:h.textDim});this.detailHeader.add(A)}renderComment(A,q){let g=A.level===0,F={0:h.accent,1:h.commentL1,2:h.commentL2,3:h.commentL3}[A.level]??h.commentL3,K=new s(this.ctx,{id:`comment-wrapper-${A.id}`,width:"100%",marginTop:1,flexDirection:"row"});if(A.level>0){let U=new s(this.ctx,{width:A.level*2,flexShrink:0});K.add(U)}let Z=new s(this.ctx,{id:`comment-${A.id}`,flexGrow:1,flexShrink:1,paddingLeft:1,paddingRight:1,borderStyle:"single",border:["left"],borderColor:F,flexDirection:"column"}),j=new o(this.ctx,{content:A.user||"[deleted]",fg:g?h.accent:h.textDim});if(Z.add(j),A.content){let U=new o(this.ctx,{content:this.stripHtml(A.content),fg:h.text,wrapMode:"word"});Z.add(U)}else if(A.deleted){let U=new o(this.ctx,{content:"[deleted]",fg:h.textMuted});Z.add(U)}if(K.add(Z),A.comments&&A.comments.length>0){let U=new s(this.ctx,{width:"100%",flexDirection:"column"});A.comments.forEach((Y)=>{let M=this.renderComment(Y);U.add(M)});let O=new s(this.ctx,{width:"100%",flexDirection:"column"});return O.add(K),O.add(U),O}return K}navigateStory(A){if(this.posts.length===0)return;if(this.selectedIndex===-1){if(A>0)this.selectStory(0);else this.selectStory(this.posts.length-1);return}let q=this.selectedIndex+A;if(q>=0&&q<this.posts.length)this.selectStory(q)}navigateToNextComment(){if(!this.selectedPost)return;if(this.rootCommentBoxes.length===0)return;let A=this.rootCommentBoxes.length-1;if(this.rootCommentIndex<A)this.rootCommentIndex++,this.scrollToRootComment(this.rootCommentIndex)}navigateToPreviousComment(){if(!this.selectedPost)return;if(this.rootCommentBoxes.length===0)return;if(this.rootCommentIndex>0)this.rootCommentIndex--,this.scrollToRootComment(this.rootCommentIndex)}scrollToRootComment(A){if(A<0||A>=this.rootCommentBoxes.length)return;let q=this.rootCommentBoxes[A];if(!q)return;let g=this.detailScroll.content,E=q.y-g.y;this.detailScroll.scrollTop=Math.max(0,E-1)}openStoryUrl(){if(!this.selectedPost)return;let A=this.selectedPost.url||`https://news.ycombinator.com/item?id=${this.selectedPost.id}`;this.callbacks.onOpenUrl?.(A)}openOnHN(){if(!this.selectedPost)return;let A=`${vH}/${this.selectedPost.id}`;this.callbacks.onOpenUrl?.(A)}openChat(){if(!this.selectedPost)return;let A=JM();if(A)this.chatProvider=A,this.showChatView();else this.showAuthSetup()}showAuthSetup(){this.authSetupMode=!0,this.authSetupStep="provider",this.authSelectedProvider="anthropic",this.detailPanel.remove(this.detailHeader.id),this.detailPanel.remove(this.detailScroll.id),this.detailPanel.remove(this.shortcutsBar.id),this.renderAuthSetup()}hideAuthSetup(){this.authSetupMode=!1;for(let A of this.detailPanel.getChildren())this.detailPanel.remove(A.id);if(this.detailPanel.add(this.detailHeader),this.detailPanel.add(this.detailScroll),this.detailPanel.add(this.shortcutsBar),this.selectedPost)this.renderDetail(this.selectedPost)}renderAuthSetup(){for(let g of this.detailPanel.getChildren())this.detailPanel.remove(g.id);let A=new s(this.ctx,{width:"100%",height:"100%",flexDirection:"column",paddingLeft:2,paddingRight:2,paddingTop:2,backgroundColor:h.bg}),q=new o(this.ctx,{content:"Set up AI Chat",fg:h.accent});if(A.add(q),A.add(new s(this.ctx,{height:1})),this.authSetupStep==="provider"){let g=new o(this.ctx,{content:"Choose your AI provider:",fg:h.text});A.add(g),A.add(new s(this.ctx,{height:1}));let E=new s(this.ctx,{flexDirection:"row",gap:1}),F=new o(this.ctx,{content:this.authSelectedProvider==="anthropic"?"\u25CF":"\u25CB",fg:this.authSelectedProvider==="anthropic"?h.accent:h.textDim}),K=new o(this.ctx,{content:"Anthropic",fg:this.authSelectedProvider==="anthropic"?h.accent:h.text});E.add(F),E.add(K),A.add(E);let Z=new s(this.ctx,{flexDirection:"row",gap:1}),j=new o(this.ctx,{content:this.authSelectedProvider==="openai"?"\u25CF":"\u25CB",fg:this.authSelectedProvider==="openai"?h.accent:h.textDim}),U=new o(this.ctx,{content:"OpenAI",fg:this.authSelectedProvider==="openai"?h.accent:h.text});Z.add(j),Z.add(U),A.add(Z),A.add(new s(this.ctx,{height:2}));let O=new o(this.ctx,{content:"\u2191/\u2193 to select, Enter to continue, Esc to cancel",fg:h.textDim});A.add(O)}else if(this.authSetupStep==="key"){let g=this.authSelectedProvider==="anthropic"?"Anthropic":"OpenAI",E=new o(this.ctx,{content:`Enter your ${g} API key:`,fg:h.text});A.add(E),A.add(new s(this.ctx,{height:1}));let F=new s(this.ctx,{width:"100%",flexDirection:"row",gap:1}),K=new o(this.ctx,{content:"\u203A",fg:h.accent});F.add(K),this.authKeyInput=new ZZ(this.ctx,{width:"100%",flexGrow:1,placeholder:this.authSelectedProvider==="anthropic"?"sk-ant-...":"sk-...",backgroundColor:h.bg}),this.authKeyInput.on("enter",()=>{this.saveApiKey()}),F.add(this.authKeyInput),A.add(F),A.add(new s(this.ctx,{height:2}));let Z=new o(this.ctx,{content:"Your key is stored locally at ~/.config/hn-cli/config.json",fg:h.textDim,wrapMode:"word"});A.add(Z),A.add(new s(this.ctx,{height:1}));let j=new o(this.ctx,{content:"This app is open source: github.com/brianlovin/hn-cli",fg:h.textDim,wrapMode:"word"});A.add(j),A.add(new s(this.ctx,{height:2}));let U=new o(this.ctx,{content:"Enter to save, Esc to cancel",fg:h.textDim});A.add(U),setTimeout(()=>{if(this.authKeyInput)this.authKeyInput.focus(),this.authKeyInput.value=""},50)}this.detailPanel.add(A)}saveApiKey(){if(!this.authKeyInput)return;let A=this.authKeyInput.value.trim();if(!A)return;let q=hg();if(q.provider=this.authSelectedProvider,this.authSelectedProvider==="anthropic")q.anthropicApiKey=A;else q.openaiApiKey=A;TK(q),this.hideAuthSetup(),this.chatProvider=this.authSelectedProvider,this.showChatView()}showSettings(){this.settingsMode=!0,this.settingsSection="main",this.settingsSelectedIndex=0;for(let A of this.detailPanel.getChildren())this.detailPanel.remove(A.id);this.renderSettings()}hideSettings(){this.settingsMode=!1;for(let A of this.detailPanel.getChildren())this.detailPanel.remove(A.id);if(this.createChatPanel(),this.chatPanel)for(let A of this.chatPanel.getChildren())this.detailPanel.add(A);if(this.chatInput)this.chatInput.focus(),this.chatInput.clear();this.renderSuggestions()}getSettingsItems(){let A=!!zg("anthropic"),q=!!zg("openai"),g=[];g.push({label:`Provider: ${this.chatProvider==="anthropic"?"Anthropic":"OpenAI"}`,action:"switch_provider",enabled:A&&q});let E=X6(this.chatProvider),K=(this.chatProvider==="anthropic"?NK:xK).find((Z)=>Z.id===E)?.name||E;if(g.push({label:`Model: ${K}`,action:"change_model",enabled:!0}),!A)g.push({label:"Add Anthropic API key",action:"add_anthropic",enabled:!0});if(!q)g.push({label:"Add OpenAI API key",action:"add_openai",enabled:!0});if(A||q)g.push({label:"Clear all API keys",action:"clear_keys",enabled:!0});return g}renderSettings(){for(let g of this.detailPanel.getChildren())this.detailPanel.remove(g.id);let A=new s(this.ctx,{width:"100%",height:"100%",flexDirection:"column",paddingLeft:2,paddingRight:2,paddingTop:2,backgroundColor:h.bg}),q=new o(this.ctx,{content:"Settings",fg:h.accent});if(A.add(q),A.add(new s(this.ctx,{height:1})),this.settingsSection==="main"){this.getSettingsItems().forEach((F,K)=>{let Z=K===this.settingsSelectedIndex,j=new s(this.ctx,{flexDirection:"row",gap:1}),U=new o(this.ctx,{content:Z?"\u203A":" ",fg:h.accent});j.add(U);let O=new o(this.ctx,{content:F.label,fg:Z?h.accent:F.enabled?h.text:h.textDim});j.add(O),A.add(j)}),A.add(new s(this.ctx,{height:2}));let E=new o(this.ctx,{content:"\u2191/\u2193 navigate Enter select Esc back",fg:h.textDim});A.add(E)}else if(this.settingsSection==="model"){let g=this.settingsModelProvider==="anthropic"?NK:xK,E=X6(this.settingsModelProvider),F=new o(this.ctx,{content:`Select ${this.settingsModelProvider==="anthropic"?"Anthropic":"OpenAI"} model:`,fg:h.text});A.add(F),A.add(new s(this.ctx,{height:1})),g.forEach((Z,j)=>{let U=j===this.settingsSelectedIndex,O=Z.id===E,Y=new s(this.ctx,{flexDirection:"row",gap:1}),M=new o(this.ctx,{content:U?"\u203A":" ",fg:h.accent});Y.add(M);let J=new o(this.ctx,{content:O?"\u25CF":"\u25CB",fg:O?h.accent:h.textDim});Y.add(J);let $=new o(this.ctx,{content:Z.name,fg:U?h.accent:h.text});Y.add($),A.add(Y)}),A.add(new s(this.ctx,{height:2}));let K=new o(this.ctx,{content:"\u2191/\u2193 navigate Enter select Esc back",fg:h.textDim});A.add(K)}this.detailPanel.add(A)}navigateSettings(A){let q;if(this.settingsSection==="main")q=this.getSettingsItems().length-1;else q=(this.settingsModelProvider==="anthropic"?NK:xK).length-1;this.settingsSelectedIndex=Math.max(0,Math.min(q,this.settingsSelectedIndex+A)),this.renderSettings()}selectSettingsItem(){if(this.settingsSection==="main"){let q=this.getSettingsItems()[this.settingsSelectedIndex];if(!q||!q.enabled)return;switch(q.action){case"switch_provider":this.chatProvider=this.chatProvider==="anthropic"?"openai":"anthropic";let g=hg();g.provider=this.chatProvider,TK(g),this.anthropic=null,this.openai=null,this.renderSettings();break;case"change_model":this.settingsSection="model",this.settingsModelProvider=this.chatProvider,this.settingsSelectedIndex=0,this.renderSettings();break;case"add_anthropic":this.hideSettings(),this.authSelectedProvider="anthropic",this.authSetupStep="key",this.authSetupMode=!0,this.chatMode=!1,this.renderAuthSetup();break;case"add_openai":this.hideSettings(),this.authSelectedProvider="openai",this.authSetupStep="key",this.authSetupMode=!0,this.chatMode=!1,this.renderAuthSetup();break;case"clear_keys":_M(),this.anthropic=null,this.openai=null,this.hideSettings(),this.hideChatView();break}}else if(this.settingsSection==="model"){let q=(this.settingsModelProvider==="anthropic"?NK:xK)[this.settingsSelectedIndex];if(q){if(MM(this.settingsModelProvider,q.id),this.settingsModelProvider==="anthropic")this.anthropic=null;else this.openai=null;this.settingsSection="main",this.settingsSelectedIndex=1,this.renderSettings()}}}navigateSuggestion(A){if(this.suggestions.length===0)return;let q=this.selectedSuggestionIndex+A;this.selectedSuggestionIndex=Math.max(0,Math.min(this.suggestions.length-1,q)),this.renderSuggestions()}selectSuggestion(){if(this.selectedSuggestionIndex<0||this.selectedSuggestionIndex>=this.suggestions.length)return;let A=this.suggestions[this.selectedSuggestionIndex];if(!A)return;if(this.chatInput)this.chatInput.clear(),this.chatInput.insertText(A);this.suggestions=[],this.selectedSuggestionIndex=-1,this.renderSuggestions(),this.sendChatMessage()}renderSuggestions(){if(!this.suggestionsContainer)return;for(let A of this.suggestionsContainer.getChildren())this.suggestionsContainer.remove(A.id);if(this.suggestionsLoading){let A=new o(this.ctx,{id:"suggestions-loading",content:`${H6.LOADING_CHARS[this.loadingFrame]??"\u280B"} Generating suggestions...`,fg:h.textDim});this.suggestionsContainer.add(A);return}if(this.suggestions.length===0)return;for(let A=0;A<this.suggestions.length;A++){let q=this.suggestions[A];if(!q)continue;let g=A===this.selectedSuggestionIndex,E=new s(this.ctx,{id:`suggestion-row-${A}`,width:"100%",flexDirection:"row",backgroundColor:h.bg}),F=new o(this.ctx,{id:`suggestion-indicator-${A}`,content:g?"\u203A ":" ",fg:h.accent,width:2});E.add(F);let K=new o(this.ctx,{id:`suggestion-text-${A}`,content:q,fg:g?h.accent:h.textDim});E.add(K),this.suggestionsContainer.add(E)}}async generateSuggestions(){if(!this.selectedPost||this.suggestionsGenerated)return;JA("[suggestions] Starting generation..."),JA("[suggestions] Provider:",this.chatProvider),this.suggestionsGenerated=!0,this.suggestionsLoading=!0;let A=setInterval(()=>{if(!this.renderer.isDestroyed&&this.suggestionsLoading)this.loadingFrame=(this.loadingFrame+1)%H6.LOADING_CHARS.length,this.renderSuggestions()},80),q=this.selectedPost,g=q.comments?.slice(0,3).map((F)=>`${F.user}: ${this.stripHtml(F.content||"").slice(0,100)}...`).join(`
184
184
  `)||"No comments yet",E=`Based on this Hacker News story, generate 3 short questions (max 10 words each) a reader might want to ask. Return ONLY the 3 questions, one per line, no numbering or bullets.
185
185
 
186
186
  Title: ${q.title}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brianlovin/hn-cli",
3
- "version": "0.1.7",
3
+ "version": "0.1.8",
4
4
  "description": "Interactive terminal UI for browsing Hacker News",
5
5
  "module": "src/index.ts",
6
6
  "type": "module",