[claude] Add session export as markdown (#288) (#304)
Some checks failed
Deploy Nexus / deploy (push) Has been cancelled

Co-authored-by: Claude (Opus 4.6) <claude@hermes.local>
Co-committed-by: Claude (Opus 4.6) <claude@hermes.local>
This commit was merged in pull request #304.
This commit is contained in:
2026-03-24 04:53:23 +00:00
committed by Timmy Time
parent e6a72ec7da
commit beee17f43c
3 changed files with 79 additions and 0 deletions

57
app.js
View File

@@ -1223,9 +1223,66 @@ window.addEventListener('player-left', (/** @type {CustomEvent} */ event) => {
console.log('Player left:', event.detail);
});
// === SESSION EXPORT ===
/** @type {{ ts: number, speaker: string, text: string }[]} */
const sessionLog = [];
const sessionStart = Date.now();
/**
* Appends an entry to the in-memory session log.
* @param {string} speaker
* @param {string} text
*/
function logMessage(speaker, text) {
sessionLog.push({ ts: Date.now(), speaker, text });
}
/**
* Formats the session log as Markdown and triggers a browser download.
*/
function exportSessionAsMarkdown() {
const startStr = new Date(sessionStart).toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
const lines = [
'# Nexus Session Export',
'',
`**Session started:** ${startStr}`,
`**Messages:** ${sessionLog.length}`,
'',
'---',
'',
];
for (const entry of sessionLog) {
const timeStr = new Date(entry.ts).toISOString().replace('T', ' ').slice(0, 19) + ' UTC';
lines.push(`### ${entry.speaker}${timeStr}`);
lines.push('');
lines.push(entry.text);
lines.push('');
}
if (sessionLog.length === 0) {
lines.push('*No messages recorded this session.*');
lines.push('');
}
const blob = new Blob([lines.join('\n')], { type: 'text/markdown' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `nexus-session-${new Date(sessionStart).toISOString().slice(0, 10)}.md`;
a.click();
URL.revokeObjectURL(url);
}
const exportBtn = document.getElementById('export-session');
if (exportBtn) {
exportBtn.addEventListener('click', exportSessionAsMarkdown);
}
window.addEventListener('chat-message', (/** @type {CustomEvent} */ event) => {
console.log('Chat message:', event.detail);
if (typeof event.detail?.text === 'string') {
logMessage(event.detail.speaker || 'TIMMY', event.detail.text);
showTimmySpeech(event.detail.text);
if (event.detail.text.toLowerCase().includes('sovereignty')) {
triggerSovereigntyEasterEgg();

View File

@@ -33,6 +33,9 @@
<button id="debug-toggle" class="chat-toggle-btn" aria-label="Toggle debug mode" style="background-color: var(--color-secondary); color: var(--color-bg); padding: 4px 8px; border-radius: 4px; font-size: 12px; cursor: pointer;">
🔍
</button>
<button id="export-session" class="chat-toggle-btn" aria-label="Export session as markdown" title="Export session log as Markdown">
📥
</button>
<audio id="ambient-sound" src="ambient.mp3" loop></audio>
</div>

View File

@@ -61,6 +61,25 @@ canvas {
margin-left: 8px;
}
/* === SESSION EXPORT === */
#export-session {
margin-left: 8px;
background-color: var(--color-secondary);
color: var(--color-text);
padding: 4px 8px;
border: none;
border-radius: 4px;
font-size: 12px;
cursor: pointer;
font-family: var(--font-body);
transition: background-color 0.2s ease;
}
#export-session:hover {
background-color: var(--color-primary);
color: var(--color-bg);
}
.collision-box {
outline: 2px solid red;
outline-offset: 2px;