claude-code-templates 1.25.0 ā 1.26.1
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.
- package/package.json +1 -1
- package/src/analytics-web/chats_mobile.html +77 -230
- package/src/chats-mobile.js +12 -11
- package/src/session-sharing.js +97 -36
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-templates",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.1",
|
|
4
4
|
"description": "CLI tool to setup Claude Code configurations with framework-specific commands, automation hooks and MCP Servers for your projects",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -755,12 +755,12 @@
|
|
|
755
755
|
stroke: rgba(63, 185, 80, 1);
|
|
756
756
|
}
|
|
757
757
|
|
|
758
|
-
.action-btn.
|
|
758
|
+
.action-btn.download-btn:hover {
|
|
759
759
|
background: rgba(59, 130, 246, 0.15);
|
|
760
760
|
color: rgba(59, 130, 246, 1);
|
|
761
761
|
}
|
|
762
762
|
|
|
763
|
-
.action-btn.
|
|
763
|
+
.action-btn.download-btn:hover svg {
|
|
764
764
|
stroke: rgba(59, 130, 246, 1);
|
|
765
765
|
}
|
|
766
766
|
|
|
@@ -2052,13 +2052,13 @@
|
|
|
2052
2052
|
</svg>
|
|
2053
2053
|
<span>Resume</span>
|
|
2054
2054
|
</button>
|
|
2055
|
-
<button class="action-btn
|
|
2055
|
+
<button class="action-btn download-btn" id="downloadConversation" onclick="downloadConversation()">
|
|
2056
2056
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2057
|
-
<path d="
|
|
2058
|
-
<polyline points="
|
|
2059
|
-
<line x1="12" y1="
|
|
2057
|
+
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
|
|
2058
|
+
<polyline points="7 10 12 15 17 10"></polyline>
|
|
2059
|
+
<line x1="12" y1="15" x2="12" y2="3"></line>
|
|
2060
2060
|
</svg>
|
|
2061
|
-
<span>
|
|
2061
|
+
<span>Download</span>
|
|
2062
2062
|
</button>
|
|
2063
2063
|
<button class="action-btn search-btn" id="chatSearchToggle">
|
|
2064
2064
|
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
@@ -2143,106 +2143,59 @@
|
|
|
2143
2143
|
</div>
|
|
2144
2144
|
</div>
|
|
2145
2145
|
|
|
2146
|
-
<!--
|
|
2147
|
-
<div class="modal-overlay" id="
|
|
2146
|
+
<!-- Download Context Modal -->
|
|
2147
|
+
<div class="modal-overlay" id="downloadModal">
|
|
2148
2148
|
<div class="modal">
|
|
2149
2149
|
<div class="modal-header" style="background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);">
|
|
2150
|
-
<span class="modal-icon"
|
|
2151
|
-
<h3 class="modal-title">
|
|
2150
|
+
<span class="modal-icon">š„</span>
|
|
2151
|
+
<h3 class="modal-title">Download Conversation Context</h3>
|
|
2152
2152
|
</div>
|
|
2153
2153
|
<div style="padding: 20px;">
|
|
2154
2154
|
<p class="modal-description" style="margin-bottom: 16px; line-height: 1.5;">
|
|
2155
|
-
|
|
2156
|
-
The generated link can be shared with others to clone your session.
|
|
2155
|
+
Download this conversation as a <strong>Markdown context file</strong> that Claude Code can read to continue your work.
|
|
2157
2156
|
</p>
|
|
2158
2157
|
|
|
2159
2158
|
<div style="background: rgba(59, 130, 246, 0.08); border-left: 3px solid #3b82f6; padding: 12px; border-radius: 6px; margin-bottom: 16px;">
|
|
2160
|
-
<h4 style="color: #3b82f6; margin: 0 0 8px 0; font-size: 14px;">š What
|
|
2159
|
+
<h4 style="color: #3b82f6; margin: 0 0 8px 0; font-size: 14px;">š What's included</h4>
|
|
2161
2160
|
<p style="margin: 0; font-size: 13px; color: var(--text-secondary); line-height: 1.4;">
|
|
2162
|
-
|
|
2161
|
+
Full conversation history (last <strong>100 messages</strong>) formatted for Claude Code to understand
|
|
2163
2162
|
</p>
|
|
2164
2163
|
</div>
|
|
2165
2164
|
|
|
2166
|
-
<div style="background: rgba(
|
|
2167
|
-
<h4 style="color: #
|
|
2168
|
-
<
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2165
|
+
<div style="background: rgba(16, 185, 129, 0.08); border-left: 3px solid #10b981; padding: 12px; border-radius: 6px; margin-bottom: 16px;">
|
|
2166
|
+
<h4 style="color: #10b981; margin: 0 0 8px 0; font-size: 14px;">š” How to continue the conversation</h4>
|
|
2167
|
+
<p style="margin: 0 0 12px 0; font-size: 13px; color: var(--text-secondary); line-height: 1.4;">
|
|
2168
|
+
After downloading, use one of these commands to load the context:
|
|
2169
|
+
</p>
|
|
2170
|
+
|
|
2171
|
+
<div style="margin-bottom: 10px;">
|
|
2172
|
+
<p style="margin: 0 0 4px 0; font-size: 12px; font-weight: 600; color: #10b981;">Option 1: Start with context loaded</p>
|
|
2173
|
+
<code style="display: block; background: rgba(0,0,0,0.5); padding: 8px; border-radius: 4px; font-size: 12px; color: #e5e7eb; overflow-x: auto; white-space: nowrap;">claude "read @context-file.md and continue"</code>
|
|
2174
|
+
</div>
|
|
2175
|
+
|
|
2176
|
+
<div>
|
|
2177
|
+
<p style="margin: 0 0 4px 0; font-size: 12px; font-weight: 600; color: #10b981;">Option 2: In interactive mode</p>
|
|
2178
|
+
<code style="display: block; background: rgba(0,0,0,0.5); padding: 8px; border-radius: 4px; font-size: 12px; color: #e5e7eb; overflow-x: auto; white-space: nowrap;">claude</code>
|
|
2179
|
+
<code style="display: block; background: rgba(0,0,0,0.5); padding: 8px; border-radius: 4px; font-size: 12px; color: #e5e7eb; overflow-x: auto; white-space: nowrap; margin-top: 4px;">> @context-file.md continue with the task</code>
|
|
2180
|
+
</div>
|
|
2174
2181
|
</div>
|
|
2175
2182
|
|
|
2176
2183
|
<div style="background: rgba(100, 116, 139, 0.08); border-left: 3px solid #64748b; padding: 12px; border-radius: 6px;">
|
|
2177
2184
|
<p style="margin: 0; font-size: 12px; color: var(--text-secondary); line-height: 1.4;">
|
|
2178
|
-
|
|
2185
|
+
š¾ <strong>Tip:</strong> Save the downloaded file in your project directory for easy access
|
|
2179
2186
|
</p>
|
|
2180
2187
|
</div>
|
|
2181
2188
|
</div>
|
|
2182
2189
|
|
|
2183
2190
|
<div class="modal-actions">
|
|
2184
|
-
<button class="modal-btn secondary" onclick="
|
|
2185
|
-
<button class="modal-btn primary" onclick="
|
|
2186
|
-
|
|
2191
|
+
<button class="modal-btn secondary" onclick="closeDownloadModal()">Cancel</button>
|
|
2192
|
+
<button class="modal-btn primary" onclick="proceedWithDownload()" style="background: #3b82f6;">
|
|
2193
|
+
Download Context File
|
|
2187
2194
|
</button>
|
|
2188
2195
|
</div>
|
|
2189
2196
|
</div>
|
|
2190
2197
|
</div>
|
|
2191
2198
|
|
|
2192
|
-
<!-- Share Modal -->
|
|
2193
|
-
<div class="modal-overlay" id="shareModal">
|
|
2194
|
-
<div class="modal">
|
|
2195
|
-
<div class="modal-header">
|
|
2196
|
-
<span class="modal-icon">š¤</span>
|
|
2197
|
-
<h3 class="modal-title">Share Conversation</h3>
|
|
2198
|
-
</div>
|
|
2199
|
-
<div id="shareModalLoading" style="text-align: center; padding: 40px; display: none;">
|
|
2200
|
-
<div class="loading-spinner"></div>
|
|
2201
|
-
<p style="margin-top: 16px; color: var(--text-secondary);">Uploading session...</p>
|
|
2202
|
-
</div>
|
|
2203
|
-
<div id="shareModalContent" style="display: none;">
|
|
2204
|
-
<p class="modal-description">
|
|
2205
|
-
Your conversation has been uploaded to x0.at. Share the command or QR code below with others.
|
|
2206
|
-
</p>
|
|
2207
|
-
<div id="shareMessageInfo" style="display: none; padding: 12px; background: var(--bg-tertiary); border-radius: 6px; margin-bottom: 16px;">
|
|
2208
|
-
<p style="font-size: 13px; color: var(--text-secondary); margin: 0;">
|
|
2209
|
-
<span id="shareMessageCount"></span>
|
|
2210
|
-
</p>
|
|
2211
|
-
</div>
|
|
2212
|
-
<div style="text-align: center; margin: 24px 0;">
|
|
2213
|
-
<div style="margin-bottom: 16px; display: flex; flex-direction: column; align-items: center;">
|
|
2214
|
-
<h4 style="margin-bottom: 12px; color: var(--text-primary);">š± Scan QR Code</h4>
|
|
2215
|
-
<img id="shareQRCode" src="" alt="QR Code" style="max-width: 300px; border-radius: 8px; border: 2px solid var(--border-color); display: block; margin: 0 auto;">
|
|
2216
|
-
<p style="font-size: 12px; color: var(--text-secondary); margin-top: 12px; margin-bottom: 0;">
|
|
2217
|
-
Scan this QR code to get the share command
|
|
2218
|
-
</p>
|
|
2219
|
-
</div>
|
|
2220
|
-
</div>
|
|
2221
|
-
<div>
|
|
2222
|
-
<h4 style="margin-bottom: 8px; color: var(--text-primary);">š Share Command</h4>
|
|
2223
|
-
<div class="modal-command" id="shareModalCommand">
|
|
2224
|
-
<!-- Command will be inserted here -->
|
|
2225
|
-
</div>
|
|
2226
|
-
</div>
|
|
2227
|
-
<div style="margin-top: 16px; padding: 12px; background: var(--bg-tertiary); border-radius: 6px;">
|
|
2228
|
-
<p style="font-size: 12px; color: var(--text-secondary); margin: 0;">
|
|
2229
|
-
š Direct URL: <a id="shareDirectUrl" href="#" target="_blank" style="color: var(--text-accent); word-break: break-all;"></a>
|
|
2230
|
-
</p>
|
|
2231
|
-
<p style="font-size: 12px; color: var(--text-warning); margin: 8px 0 0 0;">
|
|
2232
|
-
ā ļø Files kept for 3-100 days (based on size)
|
|
2233
|
-
</p>
|
|
2234
|
-
<p style="font-size: 12px; color: var(--text-secondary); margin: 4px 0 0 0;">
|
|
2235
|
-
š Files are not encrypted by default
|
|
2236
|
-
</p>
|
|
2237
|
-
</div>
|
|
2238
|
-
</div>
|
|
2239
|
-
<div class="modal-actions">
|
|
2240
|
-
<button class="modal-btn secondary" onclick="closeShareModal()">Close</button>
|
|
2241
|
-
<button class="modal-btn primary" id="copyShareCommandBtn" onclick="copyShareCommand()" style="display: none;">Copy Command</button>
|
|
2242
|
-
</div>
|
|
2243
|
-
</div>
|
|
2244
|
-
</div>
|
|
2245
|
-
|
|
2246
2199
|
<!-- Import WebSocket and Data Services -->
|
|
2247
2200
|
<script src="services/WebSocketService.js"></script>
|
|
2248
2201
|
<script src="services/DataService.js"></script>
|
|
@@ -2647,9 +2600,9 @@
|
|
|
2647
2600
|
actionButtonsGroup.style.display = 'inline-flex';
|
|
2648
2601
|
|
|
2649
2602
|
const resumeBtn = document.getElementById('resumeConversation');
|
|
2650
|
-
const
|
|
2603
|
+
const downloadBtn = document.getElementById('downloadConversation');
|
|
2651
2604
|
resumeBtn.setAttribute('data-conversation-id', conversationId);
|
|
2652
|
-
|
|
2605
|
+
downloadBtn.setAttribute('data-conversation-id', conversationId);
|
|
2653
2606
|
|
|
2654
2607
|
// Load messages (placeholder for now)
|
|
2655
2608
|
this.loadChatMessages(conversationId);
|
|
@@ -4722,70 +4675,52 @@
|
|
|
4722
4675
|
}
|
|
4723
4676
|
}
|
|
4724
4677
|
|
|
4725
|
-
//
|
|
4726
|
-
function
|
|
4727
|
-
const
|
|
4728
|
-
const conversationId =
|
|
4678
|
+
// Download conversation context functions
|
|
4679
|
+
function downloadConversation() {
|
|
4680
|
+
const downloadBtn = document.getElementById('downloadConversation');
|
|
4681
|
+
const conversationId = downloadBtn.getAttribute('data-conversation-id');
|
|
4729
4682
|
|
|
4730
4683
|
if (!conversationId) {
|
|
4731
4684
|
console.error('No conversation ID found');
|
|
4732
4685
|
return;
|
|
4733
4686
|
}
|
|
4734
4687
|
|
|
4735
|
-
console.log('
|
|
4688
|
+
console.log('š„ Opening download modal for conversation:', conversationId);
|
|
4736
4689
|
|
|
4737
|
-
// Show
|
|
4738
|
-
const
|
|
4739
|
-
|
|
4690
|
+
// Show download modal
|
|
4691
|
+
const downloadModal = document.getElementById('downloadModal');
|
|
4692
|
+
downloadModal.classList.add('show');
|
|
4740
4693
|
|
|
4741
4694
|
// Close modal when clicking outside
|
|
4742
|
-
|
|
4743
|
-
if (e.target ===
|
|
4744
|
-
|
|
4695
|
+
downloadModal.addEventListener('click', (e) => {
|
|
4696
|
+
if (e.target === downloadModal) {
|
|
4697
|
+
closeDownloadModal();
|
|
4745
4698
|
}
|
|
4746
4699
|
});
|
|
4747
4700
|
}
|
|
4748
4701
|
|
|
4749
|
-
function
|
|
4750
|
-
const
|
|
4751
|
-
|
|
4702
|
+
function closeDownloadModal() {
|
|
4703
|
+
const downloadModal = document.getElementById('downloadModal');
|
|
4704
|
+
downloadModal.classList.remove('show');
|
|
4752
4705
|
}
|
|
4753
4706
|
|
|
4754
|
-
async function
|
|
4755
|
-
// Close
|
|
4756
|
-
|
|
4707
|
+
async function proceedWithDownload() {
|
|
4708
|
+
// Close modal
|
|
4709
|
+
closeDownloadModal();
|
|
4757
4710
|
|
|
4758
|
-
const
|
|
4759
|
-
const conversationId =
|
|
4711
|
+
const downloadBtn = document.getElementById('downloadConversation');
|
|
4712
|
+
const conversationId = downloadBtn.getAttribute('data-conversation-id');
|
|
4760
4713
|
|
|
4761
4714
|
if (!conversationId) {
|
|
4762
4715
|
console.error('No conversation ID found');
|
|
4763
4716
|
return;
|
|
4764
4717
|
}
|
|
4765
4718
|
|
|
4766
|
-
console.log('
|
|
4767
|
-
|
|
4768
|
-
// Show share modal with loading state
|
|
4769
|
-
const modal = document.getElementById('shareModal');
|
|
4770
|
-
const loadingDiv = document.getElementById('shareModalLoading');
|
|
4771
|
-
const contentDiv = document.getElementById('shareModalContent');
|
|
4772
|
-
const copyBtn = document.getElementById('copyShareCommandBtn');
|
|
4773
|
-
|
|
4774
|
-
modal.classList.add('show');
|
|
4775
|
-
loadingDiv.style.display = 'block';
|
|
4776
|
-
contentDiv.style.display = 'none';
|
|
4777
|
-
copyBtn.style.display = 'none';
|
|
4778
|
-
|
|
4779
|
-
// Close modal when clicking outside
|
|
4780
|
-
modal.addEventListener('click', (e) => {
|
|
4781
|
-
if (e.target === modal) {
|
|
4782
|
-
closeShareModal();
|
|
4783
|
-
}
|
|
4784
|
-
});
|
|
4719
|
+
console.log('š„ Downloading context for conversation:', conversationId);
|
|
4785
4720
|
|
|
4786
4721
|
try {
|
|
4787
|
-
// Call API to
|
|
4788
|
-
const response = await fetch(`/api/conversations/${conversationId}/
|
|
4722
|
+
// Call API to export the conversation as markdown
|
|
4723
|
+
const response = await fetch(`/api/conversations/${conversationId}/download`, {
|
|
4789
4724
|
method: 'POST',
|
|
4790
4725
|
headers: {
|
|
4791
4726
|
'Content-Type': 'application/json'
|
|
@@ -4793,125 +4728,37 @@
|
|
|
4793
4728
|
});
|
|
4794
4729
|
|
|
4795
4730
|
if (!response.ok) {
|
|
4796
|
-
throw new Error(`Failed to
|
|
4731
|
+
throw new Error(`Failed to export session: ${response.statusText}`);
|
|
4797
4732
|
}
|
|
4798
4733
|
|
|
4799
4734
|
const data = await response.json();
|
|
4800
4735
|
|
|
4801
|
-
console.log('ā
Session
|
|
4736
|
+
console.log('ā
Session exported successfully:', data);
|
|
4802
4737
|
|
|
4803
|
-
//
|
|
4804
|
-
const
|
|
4805
|
-
const commandDiv = document.getElementById('shareModalCommand');
|
|
4806
|
-
const directUrlLink = document.getElementById('shareDirectUrl');
|
|
4807
|
-
|
|
4808
|
-
// Set QR code
|
|
4809
|
-
if (data.qrCode && data.qrCode.dataUrl) {
|
|
4810
|
-
qrCodeImg.src = data.qrCode.dataUrl;
|
|
4811
|
-
qrCodeImg.style.display = 'block';
|
|
4812
|
-
} else {
|
|
4813
|
-
qrCodeImg.style.display = 'none';
|
|
4814
|
-
}
|
|
4738
|
+
// Create a blob from the markdown content
|
|
4739
|
+
const blob = new Blob([data.markdown], { type: 'text/markdown;charset=utf-8' });
|
|
4815
4740
|
|
|
4816
|
-
//
|
|
4817
|
-
|
|
4818
|
-
|
|
4741
|
+
// Create a temporary download link
|
|
4742
|
+
const url = window.URL.createObjectURL(blob);
|
|
4743
|
+
const a = document.createElement('a');
|
|
4744
|
+
a.href = url;
|
|
4745
|
+
a.download = data.filename;
|
|
4746
|
+
document.body.appendChild(a);
|
|
4747
|
+
a.click();
|
|
4819
4748
|
|
|
4820
|
-
//
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
// Show message count information
|
|
4825
|
-
const messageInfoDiv = document.getElementById('shareMessageInfo');
|
|
4826
|
-
const messageCountSpan = document.getElementById('shareMessageCount');
|
|
4749
|
+
// Cleanup
|
|
4750
|
+
window.URL.revokeObjectURL(url);
|
|
4751
|
+
document.body.removeChild(a);
|
|
4827
4752
|
|
|
4753
|
+
// Show success notification
|
|
4754
|
+
console.log(`š„ Downloaded: ${data.filename}`);
|
|
4828
4755
|
if (data.wasLimited) {
|
|
4829
|
-
|
|
4830
|
-
messageInfoDiv.style.display = 'block';
|
|
4831
|
-
} else {
|
|
4832
|
-
messageCountSpan.innerHTML = `ā
Sharing <strong>${data.messageCount}</strong> messages from this conversation.`;
|
|
4833
|
-
messageInfoDiv.style.display = 'block';
|
|
4756
|
+
console.log(`ā ļø Exported ${data.messageCount} of ${data.totalMessageCount} messages`);
|
|
4834
4757
|
}
|
|
4835
4758
|
|
|
4836
|
-
// Show content and hide loading
|
|
4837
|
-
loadingDiv.style.display = 'none';
|
|
4838
|
-
contentDiv.style.display = 'block';
|
|
4839
|
-
copyBtn.style.display = 'block';
|
|
4840
|
-
|
|
4841
4759
|
} catch (error) {
|
|
4842
|
-
console.error('ā Failed to
|
|
4843
|
-
alert(`Failed to
|
|
4844
|
-
closeShareModal();
|
|
4845
|
-
}
|
|
4846
|
-
}
|
|
4847
|
-
|
|
4848
|
-
function closeShareModal() {
|
|
4849
|
-
const modal = document.getElementById('shareModal');
|
|
4850
|
-
modal.classList.remove('show');
|
|
4851
|
-
}
|
|
4852
|
-
|
|
4853
|
-
function copyShareCommand() {
|
|
4854
|
-
const commandDiv = document.getElementById('shareModalCommand');
|
|
4855
|
-
const copyBtn = document.getElementById('copyShareCommandBtn');
|
|
4856
|
-
const command = commandDiv.getAttribute('data-command');
|
|
4857
|
-
|
|
4858
|
-
if (!command) {
|
|
4859
|
-
console.error('No command found to copy');
|
|
4860
|
-
return;
|
|
4861
|
-
}
|
|
4862
|
-
|
|
4863
|
-
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
4864
|
-
navigator.clipboard.writeText(command).then(() => {
|
|
4865
|
-
// Show success feedback
|
|
4866
|
-
const originalText = copyBtn.textContent;
|
|
4867
|
-
copyBtn.textContent = 'ā
Copied!';
|
|
4868
|
-
copyBtn.style.backgroundColor = 'rgba(63, 185, 80, 0.8)';
|
|
4869
|
-
copyBtn.style.borderColor = 'rgba(63, 185, 80, 1)';
|
|
4870
|
-
|
|
4871
|
-
setTimeout(() => {
|
|
4872
|
-
copyBtn.textContent = originalText;
|
|
4873
|
-
copyBtn.style.backgroundColor = '';
|
|
4874
|
-
copyBtn.style.borderColor = '';
|
|
4875
|
-
}, 1500);
|
|
4876
|
-
|
|
4877
|
-
console.log('š Share command copied to clipboard:', command);
|
|
4878
|
-
}).catch(err => {
|
|
4879
|
-
console.error('Failed to copy to clipboard:', err);
|
|
4880
|
-
fallbackCopyShare(command);
|
|
4881
|
-
});
|
|
4882
|
-
} else {
|
|
4883
|
-
// Fallback for browsers without clipboard API
|
|
4884
|
-
fallbackCopyShare(command);
|
|
4885
|
-
}
|
|
4886
|
-
}
|
|
4887
|
-
|
|
4888
|
-
function fallbackCopyShare(command) {
|
|
4889
|
-
// Create a temporary text area to select and copy
|
|
4890
|
-
const tempTextArea = document.createElement('textarea');
|
|
4891
|
-
tempTextArea.value = command;
|
|
4892
|
-
tempTextArea.style.position = 'fixed';
|
|
4893
|
-
tempTextArea.style.left = '-9999px';
|
|
4894
|
-
document.body.appendChild(tempTextArea);
|
|
4895
|
-
tempTextArea.select();
|
|
4896
|
-
|
|
4897
|
-
try {
|
|
4898
|
-
document.execCommand('copy');
|
|
4899
|
-
const copyBtn = document.getElementById('copyShareCommandBtn');
|
|
4900
|
-
const originalText = copyBtn.textContent;
|
|
4901
|
-
copyBtn.textContent = 'ā
Copied!';
|
|
4902
|
-
copyBtn.style.backgroundColor = 'rgba(63, 185, 80, 0.8)';
|
|
4903
|
-
|
|
4904
|
-
setTimeout(() => {
|
|
4905
|
-
copyBtn.textContent = originalText;
|
|
4906
|
-
copyBtn.style.backgroundColor = '';
|
|
4907
|
-
}, 1500);
|
|
4908
|
-
|
|
4909
|
-
console.log('š Share command copied using fallback method:', command);
|
|
4910
|
-
} catch (err) {
|
|
4911
|
-
console.error('Fallback copy failed:', err);
|
|
4912
|
-
alert(`Please copy this command manually:\n\n${command}`);
|
|
4913
|
-
} finally {
|
|
4914
|
-
document.body.removeChild(tempTextArea);
|
|
4760
|
+
console.error('ā Failed to download context:', error);
|
|
4761
|
+
alert(`Failed to download context: ${error.message}`);
|
|
4915
4762
|
}
|
|
4916
4763
|
}
|
|
4917
4764
|
|
package/src/chats-mobile.js
CHANGED
|
@@ -478,8 +478,8 @@ class ChatsMobile {
|
|
|
478
478
|
}
|
|
479
479
|
});
|
|
480
480
|
|
|
481
|
-
// API to
|
|
482
|
-
this.app.post('/api/conversations/:id/
|
|
481
|
+
// API to download a conversation session as markdown
|
|
482
|
+
this.app.post('/api/conversations/:id/download', async (req, res) => {
|
|
483
483
|
try {
|
|
484
484
|
const conversationId = req.params.id;
|
|
485
485
|
const conversation = this.data.conversations.find(conv => conv.id === conversationId);
|
|
@@ -488,24 +488,25 @@ class ChatsMobile {
|
|
|
488
488
|
return res.status(404).json({ error: 'Conversation not found' });
|
|
489
489
|
}
|
|
490
490
|
|
|
491
|
-
console.log(chalk.cyan(
|
|
491
|
+
console.log(chalk.cyan(`š„ Exporting conversation ${conversationId} as markdown...`));
|
|
492
492
|
|
|
493
|
-
//
|
|
494
|
-
const
|
|
493
|
+
// Export the session as markdown using SessionSharing module
|
|
494
|
+
const exportResult = await this.sessionSharing.exportSessionAsMarkdown(conversationId, conversation);
|
|
495
495
|
|
|
496
496
|
res.json({
|
|
497
497
|
success: true,
|
|
498
498
|
conversationId: conversationId,
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
499
|
+
markdown: exportResult.markdown,
|
|
500
|
+
filename: exportResult.filename,
|
|
501
|
+
messageCount: exportResult.messageCount,
|
|
502
|
+
totalMessageCount: exportResult.totalMessageCount,
|
|
503
|
+
wasLimited: exportResult.wasLimited,
|
|
503
504
|
timestamp: new Date().toISOString()
|
|
504
505
|
});
|
|
505
506
|
} catch (error) {
|
|
506
|
-
console.error('Error
|
|
507
|
+
console.error('Error exporting conversation:', error);
|
|
507
508
|
res.status(500).json({
|
|
508
|
-
error: 'Failed to
|
|
509
|
+
error: 'Failed to export session',
|
|
509
510
|
message: error.message
|
|
510
511
|
});
|
|
511
512
|
}
|
package/src/session-sharing.js
CHANGED
|
@@ -8,62 +8,123 @@ const execAsync = promisify(exec);
|
|
|
8
8
|
const QRCode = require('qrcode');
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* SessionSharing - Handles exporting
|
|
12
|
-
* Uses x0.at - a simple, reliable file hosting service
|
|
11
|
+
* SessionSharing - Handles exporting Claude Code sessions as downloadable context
|
|
13
12
|
*/
|
|
14
13
|
class SessionSharing {
|
|
15
14
|
constructor(conversationAnalyzer) {
|
|
16
15
|
this.conversationAnalyzer = conversationAnalyzer;
|
|
17
|
-
this.uploadService = 'x0.at';
|
|
18
|
-
this.uploadUrl = 'https://x0.at';
|
|
19
16
|
}
|
|
20
17
|
|
|
21
18
|
/**
|
|
22
|
-
* Export
|
|
23
|
-
* @param {string} conversationId - Conversation ID to
|
|
19
|
+
* Export conversation session as downloadable markdown file
|
|
20
|
+
* @param {string} conversationId - Conversation ID to export
|
|
24
21
|
* @param {Object} conversationData - Full conversation data object
|
|
25
|
-
* @param {Object} options -
|
|
26
|
-
* @returns {Promise<Object>}
|
|
22
|
+
* @param {Object} options - Export options (messageLimit, etc.)
|
|
23
|
+
* @returns {Promise<Object>} Export result with markdown content and filename
|
|
27
24
|
*/
|
|
28
|
-
async
|
|
29
|
-
console.log(chalk.blue(
|
|
25
|
+
async exportSessionAsMarkdown(conversationId, conversationData, options = {}) {
|
|
26
|
+
console.log(chalk.blue(`š„ Preparing session ${conversationId} for download...`));
|
|
30
27
|
|
|
31
28
|
try {
|
|
32
|
-
// 1.
|
|
33
|
-
const
|
|
29
|
+
// 1. Get conversation messages
|
|
30
|
+
const allMessages = await this.conversationAnalyzer.getParsedConversation(conversationData.filePath);
|
|
34
31
|
|
|
35
|
-
//
|
|
36
|
-
const
|
|
32
|
+
// Limit messages to avoid large file sizes (default: last 100 messages)
|
|
33
|
+
const messageLimit = options.messageLimit || 100;
|
|
34
|
+
const messages = allMessages.slice(-messageLimit);
|
|
37
35
|
|
|
38
|
-
//
|
|
39
|
-
const
|
|
36
|
+
// 2. Convert to markdown format
|
|
37
|
+
const markdown = this.convertToMarkdown(messages, conversationData, {
|
|
38
|
+
messageCount: messages.length,
|
|
39
|
+
totalMessageCount: allMessages.length,
|
|
40
|
+
wasLimited: allMessages.length > messageLimit
|
|
41
|
+
});
|
|
40
42
|
|
|
41
|
-
//
|
|
42
|
-
const
|
|
43
|
+
// 3. Generate filename
|
|
44
|
+
const projectName = (conversationData.project || 'session').replace(/[^a-zA-Z0-9-_]/g, '-');
|
|
45
|
+
const date = new Date().toISOString().split('T')[0];
|
|
46
|
+
const filename = `claude-context-${projectName}-${date}.md`;
|
|
43
47
|
|
|
44
|
-
console.log(chalk.green(`ā
Session
|
|
45
|
-
console.log(chalk.
|
|
46
|
-
console.log(chalk.gray(`š Direct URL: ${uploadUrl}`));
|
|
47
|
-
console.log(chalk.yellow(`ā ļø Files kept for 3-100 days (based on size)`));
|
|
48
|
-
console.log(chalk.gray(`š Note: Files are not encrypted by default`));
|
|
48
|
+
console.log(chalk.green(`ā
Session exported successfully!`));
|
|
49
|
+
console.log(chalk.gray(`š Exported ${messages.length} messages`));
|
|
49
50
|
|
|
50
51
|
return {
|
|
51
52
|
success: true,
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
messageCount: sessionExport.conversation.messageCount,
|
|
58
|
-
totalMessageCount: sessionExport.conversation.totalMessageCount,
|
|
59
|
-
wasLimited: sessionExport.conversation.wasLimited
|
|
53
|
+
markdown,
|
|
54
|
+
filename,
|
|
55
|
+
messageCount: messages.length,
|
|
56
|
+
totalMessageCount: allMessages.length,
|
|
57
|
+
wasLimited: allMessages.length > messageLimit
|
|
60
58
|
};
|
|
61
59
|
} catch (error) {
|
|
62
|
-
console.error(chalk.red('ā Failed to
|
|
60
|
+
console.error(chalk.red('ā Failed to export session:'), error.message);
|
|
63
61
|
throw error;
|
|
64
62
|
}
|
|
65
63
|
}
|
|
66
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Convert conversation messages to markdown format optimized for Claude Code
|
|
67
|
+
* @param {Array} messages - Parsed conversation messages
|
|
68
|
+
* @param {Object} conversationData - Conversation metadata
|
|
69
|
+
* @param {Object} stats - Export statistics
|
|
70
|
+
* @returns {string} Markdown formatted content
|
|
71
|
+
*/
|
|
72
|
+
convertToMarkdown(messages, conversationData, stats) {
|
|
73
|
+
const lines = [];
|
|
74
|
+
|
|
75
|
+
// Header for Claude Code
|
|
76
|
+
lines.push('# Previous Conversation Context\n');
|
|
77
|
+
lines.push('> **Note to Claude Code**: This file contains the complete conversation history from a previous session. Read and understand this context to continue helping the user with their task.\n');
|
|
78
|
+
lines.push(`**Project:** ${conversationData.project || 'Unknown'}`);
|
|
79
|
+
lines.push(`**Date:** ${new Date().toISOString().split('T')[0]}`);
|
|
80
|
+
lines.push(`**Messages in this export:** ${stats.messageCount}${stats.wasLimited ? ` (most recent from a total of ${stats.totalMessageCount})` : ''}`);
|
|
81
|
+
lines.push('');
|
|
82
|
+
lines.push('---');
|
|
83
|
+
lines.push('');
|
|
84
|
+
|
|
85
|
+
// Conversation
|
|
86
|
+
lines.push('## š¬ Conversation History\n');
|
|
87
|
+
|
|
88
|
+
messages.forEach((msg, index) => {
|
|
89
|
+
const role = msg.role === 'user' ? 'š¤ User' : 'š¤ Assistant';
|
|
90
|
+
const timestamp = new Date(msg.timestamp).toLocaleString();
|
|
91
|
+
|
|
92
|
+
lines.push(`### Message ${index + 1}: ${role}`);
|
|
93
|
+
lines.push(`*${timestamp}*\n`);
|
|
94
|
+
|
|
95
|
+
// Extract text content from message
|
|
96
|
+
if (Array.isArray(msg.content)) {
|
|
97
|
+
msg.content.forEach(block => {
|
|
98
|
+
if (block.type === 'text') {
|
|
99
|
+
lines.push(block.text);
|
|
100
|
+
} else if (block.type === 'tool_use') {
|
|
101
|
+
lines.push(`\`\`\`${block.name || 'tool'}`);
|
|
102
|
+
lines.push(JSON.stringify(block.input || {}, null, 2));
|
|
103
|
+
lines.push('```');
|
|
104
|
+
} else if (block.type === 'tool_result') {
|
|
105
|
+
lines.push('**Tool Result:**');
|
|
106
|
+
lines.push('```');
|
|
107
|
+
lines.push(typeof block.content === 'string' ? block.content : JSON.stringify(block.content, null, 2));
|
|
108
|
+
lines.push('```');
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
} else if (typeof msg.content === 'string') {
|
|
112
|
+
lines.push(msg.content);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
lines.push('');
|
|
116
|
+
lines.push('---');
|
|
117
|
+
lines.push('');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Footer
|
|
121
|
+
lines.push('\n---');
|
|
122
|
+
lines.push('');
|
|
123
|
+
lines.push('*Generated by Claude Code Templates - [aitmpl.com](https://aitmpl.com)*');
|
|
124
|
+
|
|
125
|
+
return lines.join('\n');
|
|
126
|
+
}
|
|
127
|
+
|
|
67
128
|
/**
|
|
68
129
|
* Export session data to standardized format
|
|
69
130
|
* @param {string} conversationId - Conversation ID
|
|
@@ -117,14 +178,14 @@ class SessionSharing {
|
|
|
117
178
|
exported_at: new Date().toISOString(),
|
|
118
179
|
conversation: {
|
|
119
180
|
id: conversationId,
|
|
120
|
-
project: conversationData.project || '
|
|
181
|
+
project: conversationData.project || 'shared-session',
|
|
121
182
|
created: conversationData.created,
|
|
122
183
|
lastModified: conversationData.lastModified,
|
|
123
184
|
messageCount: messages.length,
|
|
124
185
|
totalMessageCount: allMessages.length,
|
|
125
186
|
wasLimited: allMessages.length > messageLimit,
|
|
126
187
|
tokens: conversationData.tokens,
|
|
127
|
-
model: conversationData.modelInfo?.primaryModel || '
|
|
188
|
+
model: conversationData.modelInfo?.primaryModel || 'claude-sonnet-4-5-20250929'
|
|
128
189
|
},
|
|
129
190
|
messages: jsonlMessages,
|
|
130
191
|
metadata: {
|
|
@@ -223,8 +284,8 @@ class SessionSharing {
|
|
|
223
284
|
console.log(chalk.green(`\nā
Session installed successfully!`));
|
|
224
285
|
console.log(chalk.cyan(`š Location: ${installResult.sessionPath}`));
|
|
225
286
|
|
|
226
|
-
// Show resume command
|
|
227
|
-
const resumeCommand = `claude --resume ${installResult.
|
|
287
|
+
// Show resume command (only conversation ID needed)
|
|
288
|
+
const resumeCommand = `claude --resume ${installResult.conversationId}`;
|
|
228
289
|
console.log(chalk.yellow(`\nš” To continue this conversation, run:`));
|
|
229
290
|
console.log(chalk.white(`\n ${resumeCommand}\n`));
|
|
230
291
|
console.log(chalk.gray(` Or open Claude Code to see it in your sessions list`));
|