vg-coder-cli 1.0.15 → 1.0.16

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vg-coder-cli",
3
- "version": "1.0.15",
3
+ "version": "1.0.16",
4
4
  "description": "🚀 CLI tool to analyze projects, concatenate source files, count tokens, and export HTML with syntax highlighting and copy functionality",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -363,6 +363,10 @@
363
363
  <span id="analyze-copy-icon">📋</span>
364
364
  <span id="analyze-copy-text">Copy to Clipboard</span>
365
365
  </button>
366
+ <button class="btn btn-copy" onclick="copyAnalyzeAsFile()">
367
+ <span id="analyze-file-icon">📄</span>
368
+ <span id="analyze-file-text">Copy as File</span>
369
+ </button>
366
370
  </div>
367
371
  <div class="response" id="analyze-response"></div>
368
372
  </div>
@@ -672,6 +676,75 @@ API sẽ:
672
676
  }
673
677
  }
674
678
 
679
+ async function copyAsFile(filename, content) {
680
+ const blob = new Blob([content], {
681
+ type: "application/octet-stream"
682
+ });
683
+
684
+ // ClipboardItem cần type key phải trùng blob.type
685
+ const item = new ClipboardItem(
686
+ { [blob.type]: blob },
687
+ {
688
+ // Không phải chuẩn, nhưng Chrome hỗ trợ unofficial metadata
689
+ type: "application/octet-stream",
690
+ presentationStyle: "attachment",
691
+ name: filename
692
+ }
693
+ );
694
+
695
+ await navigator.clipboard.write([item]);
696
+ }
697
+
698
+ async function copyAnalyzeAsFile() {
699
+ const copyBtn = event.target.closest('.btn-copy');
700
+ const copyIcon = document.getElementById('analyze-file-icon');
701
+ const copyText = document.getElementById('analyze-file-text');
702
+
703
+ if (!lastAnalyzeResult) {
704
+ // Fetch if not already analyzed
705
+ const path = document.getElementById('analyze-path').value;
706
+ showLoading(copyBtn, '<span id="analyze-file-icon">📄</span><span id="analyze-file-text">Copy as File</span>');
707
+
708
+ try {
709
+ const res = await fetch(`${API_BASE}/api/analyze`, {
710
+ method: 'POST',
711
+ headers: { 'Content-Type': 'application/json' },
712
+ body: JSON.stringify({ path })
713
+ });
714
+
715
+ if (res.ok) {
716
+ lastAnalyzeResult = await res.text();
717
+ } else {
718
+ showToast('❌ Lỗi analyze!', 'error');
719
+ resetButton(copyBtn);
720
+ return;
721
+ }
722
+ } catch (err) {
723
+ showToast('❌ Lỗi: ' + err.message, 'error');
724
+ resetButton(copyBtn);
725
+ return;
726
+ }
727
+ resetButton(copyBtn);
728
+ }
729
+
730
+ try {
731
+ await copyAsFile("project.txt", lastAnalyzeResult);
732
+
733
+ copyBtn.classList.add('copied');
734
+ copyIcon.textContent = '✓';
735
+ copyText.textContent = 'Copied!';
736
+ showToast('✅ Đã copy project.txt như file!', 'success');
737
+
738
+ setTimeout(() => {
739
+ copyBtn.classList.remove('copied');
740
+ copyIcon.textContent = '📄';
741
+ copyText.textContent = 'Copy as File';
742
+ }, 2000);
743
+ } catch (err) {
744
+ showToast('❌ Lỗi copy: ' + err.message, 'error');
745
+ }
746
+ }
747
+
675
748
  async function testExecute() {
676
749
  const btn = event.target.closest('.btn');
677
750
  const bash = document.getElementById('execute-bash').value;