@@ -106,8 +106,9 @@ class EurusChat {
106106 }
107107
108108 autoSendSessionKeys ( ) {
109- // After WS connects, if we have session-stored keys and server has none, auto-send them
110- if ( this . serverKeysPresent . openai || this . keysConfigured ) return ;
109+ // After WS (re)connects, resend saved keys so the new server-side session gets them.
110+ // Only skip if the server has pre-configured env keys (not user-provided).
111+ if ( this . serverKeysPresent . openai ) return ;
111112 const saved = sessionStorage . getItem ( 'eurus-keys' ) ;
112113 if ( ! saved ) return ;
113114 try {
@@ -192,11 +193,13 @@ class EurusChat {
192193 this . reconnectAttempts = 0 ;
193194 this . updateConnectionStatus ( 'connected' ) ;
194195
196+ // Always resend keys on (re)connect — server session may have been
197+ // destroyed on disconnect, so keys stored in sessionStorage must be
198+ // re-sent even if keysConfigured is true from the previous session.
199+ this . autoSendSessionKeys ( ) ;
200+
195201 if ( this . serverKeysPresent . openai || this . keysConfigured ) {
196202 this . sendBtn . disabled = false ;
197- } else {
198- // Auto-send keys from sessionStorage on reconnect/refresh
199- this . autoSendSessionKeys ( ) ;
200203 }
201204 } ;
202205
@@ -700,17 +703,47 @@ class EurusChat {
700703 const actionsDiv = lastFigure ? lastFigure . querySelector ( '.plot-actions' ) : null ;
701704
702705 if ( actionsDiv ) {
706+ // Check if an Arraylake button already exists on this figure
707+ const existingBtn = actionsDiv . querySelector ( '.arraylake-btn' ) ;
708+ if ( existingBtn ) {
709+ // Append new snippet to the existing code block
710+ const existingCodeDiv = lastFigure . querySelector ( '.arraylake-code-block' ) ;
711+ if ( existingCodeDiv ) {
712+ const codeEl = existingCodeDiv . querySelector ( 'code' ) ;
713+ const prevRaw = existingCodeDiv . getAttribute ( 'data-raw-code' ) || '' ;
714+ const combined = prevRaw + '\n\n# ---\n\n' + cleanCode ;
715+ existingCodeDiv . setAttribute ( 'data-raw-code' , combined ) ;
716+ try {
717+ codeEl . innerHTML = hljs . highlight ( combined , { language : 'python' } ) . value ;
718+ } catch ( e ) {
719+ codeEl . textContent = combined ;
720+ }
721+ // Update copy button target
722+ const copyBtn = existingCodeDiv . querySelector ( '.copy-snippet-btn' ) ;
723+ if ( copyBtn ) {
724+ copyBtn . onclick = ( ) => {
725+ navigator . clipboard . writeText ( combined ) . then ( ( ) => {
726+ copyBtn . textContent = '✓ Copied!' ;
727+ setTimeout ( ( ) => copyBtn . textContent = 'Copy Code' , 2000 ) ;
728+ } ) ;
729+ } ;
730+ }
731+ }
732+ return ;
733+ }
734+
703735 // Add button inline with Enlarge/Download/Show Code
704736 const btn = document . createElement ( 'button' ) ;
705- btn . className = 'code-btn' ;
737+ btn . className = 'code-btn arraylake-btn ' ;
706738 btn . title = 'Arraylake Code' ;
707739 btn . textContent = '📦 Arraylake Code' ;
708740 actionsDiv . appendChild ( btn ) ;
709741
710742 // Add code block to figure (same pattern as Show Code)
711743 const codeDiv = document . createElement ( 'div' ) ;
712- codeDiv . className = 'plot-code' ;
744+ codeDiv . className = 'plot-code arraylake-code-block ' ;
713745 codeDiv . style . display = 'none' ;
746+ codeDiv . setAttribute ( 'data-raw-code' , cleanCode ) ;
714747
715748 const pre = document . createElement ( 'pre' ) ;
716749 const codeEl = document . createElement ( 'code' ) ;
@@ -728,7 +761,8 @@ class EurusChat {
728761 copyBtn . className = 'copy-snippet-btn' ;
729762 copyBtn . textContent = 'Copy Code' ;
730763 copyBtn . addEventListener ( 'click' , ( ) => {
731- navigator . clipboard . writeText ( cleanCode ) . then ( ( ) => {
764+ const rawCode = codeDiv . getAttribute ( 'data-raw-code' ) || cleanCode ;
765+ navigator . clipboard . writeText ( rawCode ) . then ( ( ) => {
732766 copyBtn . textContent = '✓ Copied!' ;
733767 setTimeout ( ( ) => copyBtn . textContent = 'Copy Code' , 2000 ) ;
734768 } ) ;
@@ -747,17 +781,35 @@ class EurusChat {
747781 }
748782 } ) ;
749783 } else {
750- // No plot figure — add as standalone section under the message
784+ // No plot figure — check if standalone section already exists
785+ const existingWrapper = targetMsg . querySelector ( '.arraylake-snippet-section' ) ;
786+ if ( existingWrapper ) {
787+ // Append to existing standalone snippet
788+ const codeEl = existingWrapper . querySelector ( 'code' ) ;
789+ const existingCodeDiv = existingWrapper . querySelector ( '.plot-code' ) ;
790+ const prevRaw = existingCodeDiv . getAttribute ( 'data-raw-code' ) || '' ;
791+ const combined = prevRaw + '\n\n# ---\n\n' + cleanCode ;
792+ existingCodeDiv . setAttribute ( 'data-raw-code' , combined ) ;
793+ try {
794+ codeEl . innerHTML = hljs . highlight ( combined , { language : 'python' } ) . value ;
795+ } catch ( e ) {
796+ codeEl . textContent = combined ;
797+ }
798+ return ;
799+ }
800+
751801 const wrapper = document . createElement ( 'div' ) ;
752802 wrapper . className = 'arraylake-snippet-section' ;
753803 wrapper . innerHTML = `
754804 <div class="plot-actions">
755- <button class="code-btn" title="Arraylake Code">📦 Arraylake Code</button>
805+ <button class="code-btn arraylake-btn " title="Arraylake Code">📦 Arraylake Code</button>
756806 </div>
757807 <div class="plot-code" style="display: none;">
758808 <pre><code class="language-python hljs"></code></pre>
759809 </div>
760810 ` ;
811+ const codeDivEl = wrapper . querySelector ( '.plot-code' ) ;
812+ codeDivEl . setAttribute ( 'data-raw-code' , cleanCode ) ;
761813 const codeEl = wrapper . querySelector ( 'code' ) ;
762814 try {
763815 codeEl . innerHTML = hljs . highlight ( cleanCode , { language : 'python' } ) . value ;
0 commit comments