claude-code-workflow 6.3.26 → 6.3.28

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 (129) hide show
  1. package/.claude/CLAUDE.md +7 -1
  2. package/.claude/agents/action-planning-agent.md +1 -0
  3. package/.claude/agents/cli-discuss-agent.md +391 -0
  4. package/.claude/agents/cli-execution-agent.md +2 -0
  5. package/.claude/agents/cli-explore-agent.md +2 -1
  6. package/.claude/agents/cli-lite-planning-agent.md +1 -0
  7. package/.claude/agents/cli-planning-agent.md +1 -0
  8. package/.claude/agents/code-developer.md +1 -0
  9. package/.claude/agents/conceptual-planning-agent.md +2 -0
  10. package/.claude/agents/context-search-agent.md +1 -0
  11. package/.claude/agents/debug-explore-agent.md +2 -0
  12. package/.claude/agents/doc-generator.md +1 -0
  13. package/.claude/agents/issue-plan-agent.md +2 -1
  14. package/.claude/agents/issue-queue-agent.md +2 -1
  15. package/.claude/agents/memory-bridge.md +2 -0
  16. package/.claude/agents/test-context-search-agent.md +2 -0
  17. package/.claude/agents/test-fix-agent.md +1 -0
  18. package/.claude/agents/ui-design-agent.md +2 -0
  19. package/.claude/agents/universal-executor.md +1 -0
  20. package/.claude/commands/issue/execute.md +141 -163
  21. package/.claude/commands/workflow/lite-lite-lite.md +798 -0
  22. package/.claude/commands/workflow/multi-cli-plan.md +510 -0
  23. package/.claude/skills/ccw/SKILL.md +262 -372
  24. package/.claude/skills/ccw/command.json +547 -0
  25. package/.claude/skills/ccw-help/SKILL.md +46 -107
  26. package/.claude/skills/ccw-help/command.json +511 -0
  27. package/.claude/skills/skill-tuning/SKILL.md +303 -0
  28. package/.claude/skills/skill-tuning/phases/actions/action-abort.md +164 -0
  29. package/.claude/skills/skill-tuning/phases/actions/action-analyze-requirements.md +406 -0
  30. package/.claude/skills/skill-tuning/phases/actions/action-apply-fix.md +206 -0
  31. package/.claude/skills/skill-tuning/phases/actions/action-complete.md +195 -0
  32. package/.claude/skills/skill-tuning/phases/actions/action-diagnose-agent.md +317 -0
  33. package/.claude/skills/skill-tuning/phases/actions/action-diagnose-context.md +243 -0
  34. package/.claude/skills/skill-tuning/phases/actions/action-diagnose-dataflow.md +318 -0
  35. package/.claude/skills/skill-tuning/phases/actions/action-diagnose-docs.md +299 -0
  36. package/.claude/skills/skill-tuning/phases/actions/action-diagnose-memory.md +269 -0
  37. package/.claude/skills/skill-tuning/phases/actions/action-diagnose-token-consumption.md +200 -0
  38. package/.claude/skills/skill-tuning/phases/actions/action-gemini-analysis.md +322 -0
  39. package/.claude/skills/skill-tuning/phases/actions/action-generate-report.md +228 -0
  40. package/.claude/skills/skill-tuning/phases/actions/action-init.md +149 -0
  41. package/.claude/skills/skill-tuning/phases/actions/action-propose-fixes.md +317 -0
  42. package/.claude/skills/skill-tuning/phases/actions/action-verify.md +222 -0
  43. package/.claude/skills/skill-tuning/phases/orchestrator.md +377 -0
  44. package/.claude/skills/skill-tuning/phases/state-schema.md +378 -0
  45. package/.claude/skills/skill-tuning/specs/category-mappings.json +284 -0
  46. package/.claude/skills/skill-tuning/specs/dimension-mapping.md +212 -0
  47. package/.claude/skills/skill-tuning/specs/problem-taxonomy.md +318 -0
  48. package/.claude/skills/skill-tuning/specs/quality-gates.md +263 -0
  49. package/.claude/skills/skill-tuning/specs/skill-authoring-principles.md +189 -0
  50. package/.claude/skills/skill-tuning/specs/tuning-strategies.md +1537 -0
  51. package/.claude/skills/skill-tuning/templates/diagnosis-report.md +153 -0
  52. package/.claude/skills/skill-tuning/templates/fix-proposal.md +204 -0
  53. package/.claude/workflows/cli-templates/schemas/multi-cli-discussion-schema.json +421 -0
  54. package/.claude/workflows/cli-tools-usage.md +0 -41
  55. package/ccw/dist/core/auth/csrf-middleware.d.ts.map +1 -1
  56. package/ccw/dist/core/auth/csrf-middleware.js +3 -1
  57. package/ccw/dist/core/auth/csrf-middleware.js.map +1 -1
  58. package/ccw/dist/core/data-aggregator.d.ts +2 -0
  59. package/ccw/dist/core/data-aggregator.d.ts.map +1 -1
  60. package/ccw/dist/core/data-aggregator.js +5 -2
  61. package/ccw/dist/core/data-aggregator.js.map +1 -1
  62. package/ccw/dist/core/lite-scanner.d.ts +2 -1
  63. package/ccw/dist/core/lite-scanner.d.ts.map +1 -1
  64. package/ccw/dist/core/lite-scanner.js +295 -6
  65. package/ccw/dist/core/lite-scanner.js.map +1 -1
  66. package/ccw/dist/core/routes/codexlens/config-handlers.d.ts.map +1 -1
  67. package/ccw/dist/core/routes/codexlens/config-handlers.js +5 -5
  68. package/ccw/dist/core/routes/codexlens/config-handlers.js.map +1 -1
  69. package/ccw/dist/core/routes/session-routes.d.ts.map +1 -1
  70. package/ccw/dist/core/routes/session-routes.js +166 -48
  71. package/ccw/dist/core/routes/session-routes.js.map +1 -1
  72. package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
  73. package/ccw/dist/core/routes/system-routes.js +87 -0
  74. package/ccw/dist/core/routes/system-routes.js.map +1 -1
  75. package/ccw/dist/core/server.js +2 -2
  76. package/ccw/dist/core/server.js.map +1 -1
  77. package/ccw/scripts/IMPLEMENTATION-SUMMARY.md +226 -0
  78. package/ccw/scripts/QUICK-REFERENCE.md +135 -0
  79. package/ccw/scripts/README-memory-embedder.md +157 -0
  80. package/ccw/scripts/__pycache__/memory_embedder.cpython-313.pyc +0 -0
  81. package/ccw/scripts/__pycache__/test_memory_embedder.cpython-313-pytest-8.4.2.pyc +0 -0
  82. package/ccw/scripts/memory-embedder-example.ts +184 -0
  83. package/ccw/scripts/memory_embedder.py +428 -0
  84. package/ccw/scripts/test_memory_embedder.py +245 -0
  85. package/ccw/src/core/auth/csrf-middleware.ts +3 -1
  86. package/ccw/src/core/data-aggregator.ts +7 -2
  87. package/ccw/src/core/lite-scanner.ts +440 -6
  88. package/ccw/src/core/routes/codexlens/config-handlers.ts +12 -9
  89. package/ccw/src/core/routes/session-routes.ts +201 -48
  90. package/ccw/src/core/routes/system-routes.ts +102 -0
  91. package/ccw/src/core/server.ts +2 -2
  92. package/ccw/src/templates/dashboard-css/01-base.css +8 -0
  93. package/ccw/src/templates/dashboard-css/02-session.css +81 -0
  94. package/ccw/src/templates/dashboard-css/04-lite-tasks.css +2442 -0
  95. package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +157 -0
  96. package/ccw/src/templates/dashboard-css/32-issue-manager.css +23 -0
  97. package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +38 -4
  98. package/ccw/src/templates/dashboard-js/components/hook-manager.js +38 -13
  99. package/ccw/src/templates/dashboard-js/components/navigation.js +24 -4
  100. package/ccw/src/templates/dashboard-js/i18n.js +194 -6
  101. package/ccw/src/templates/dashboard-js/views/api-settings.js +32 -0
  102. package/ccw/src/templates/dashboard-js/views/claude-manager.js +44 -3
  103. package/ccw/src/templates/dashboard-js/views/cli-manager.js +303 -31
  104. package/ccw/src/templates/dashboard-js/views/history.js +44 -6
  105. package/ccw/src/templates/dashboard-js/views/home.js +1 -0
  106. package/ccw/src/templates/dashboard-js/views/issue-manager.js +54 -7
  107. package/ccw/src/templates/dashboard-js/views/lite-tasks.js +1817 -4
  108. package/ccw/src/templates/dashboard.html +5 -0
  109. package/package.json +2 -1
  110. package/.claude/skills/ccw/index/command-capabilities.json +0 -127
  111. package/.claude/skills/ccw/index/intent-rules.json +0 -136
  112. package/.claude/skills/ccw/index/workflow-chains.json +0 -451
  113. package/.claude/skills/ccw/phases/actions/bugfix.md +0 -218
  114. package/.claude/skills/ccw/phases/actions/coupled.md +0 -194
  115. package/.claude/skills/ccw/phases/actions/docs.md +0 -93
  116. package/.claude/skills/ccw/phases/actions/full.md +0 -154
  117. package/.claude/skills/ccw/phases/actions/issue.md +0 -201
  118. package/.claude/skills/ccw/phases/actions/rapid.md +0 -104
  119. package/.claude/skills/ccw/phases/actions/review-fix.md +0 -84
  120. package/.claude/skills/ccw/phases/actions/tdd.md +0 -66
  121. package/.claude/skills/ccw/phases/actions/ui.md +0 -79
  122. package/.claude/skills/ccw/phases/orchestrator.md +0 -435
  123. package/.claude/skills/ccw/specs/intent-classification.md +0 -336
  124. package/.claude/skills/ccw-help/index/all-agents.json +0 -82
  125. package/.claude/skills/ccw-help/index/all-commands.json +0 -882
  126. package/.claude/skills/ccw-help/index/by-category.json +0 -914
  127. package/.claude/skills/ccw-help/index/by-use-case.json +0 -896
  128. package/.claude/skills/ccw-help/index/command-relationships.json +0 -160
  129. package/.claude/skills/ccw-help/index/essential-commands.json +0 -112
@@ -395,6 +395,10 @@ async function updateCliToolConfig(tool, updates) {
395
395
  }
396
396
  if (data.success && cliToolConfig && cliToolConfig.tools) {
397
397
  cliToolConfig.tools[tool] = data.config;
398
+ // Invalidate cache to ensure fresh data on page refresh
399
+ if (window.cacheManager) {
400
+ window.cacheManager.invalidate('cli-config');
401
+ }
398
402
  }
399
403
  return data;
400
404
  } catch (err) {
@@ -554,6 +558,298 @@ function buildToolConfigModalContent(tool, config, models, status) {
554
558
  '</div>';
555
559
  }
556
560
 
561
+ // ========== File Browser Modal ==========
562
+
563
+ var fileBrowserState = {
564
+ currentPath: '',
565
+ showHidden: false,
566
+ onSelect: null
567
+ };
568
+
569
+ function showFileBrowserModal(onSelect) {
570
+ fileBrowserState.onSelect = onSelect;
571
+ fileBrowserState.showHidden = false;
572
+
573
+ // Create modal overlay
574
+ var overlay = document.createElement('div');
575
+ overlay.id = 'fileBrowserOverlay';
576
+ overlay.className = 'modal-overlay';
577
+ overlay.innerHTML = buildFileBrowserModalContent();
578
+ document.body.appendChild(overlay);
579
+
580
+ // Load initial directory (home)
581
+ loadFileBrowserDirectory('');
582
+
583
+ // Initialize events
584
+ initFileBrowserEvents();
585
+
586
+ // Initialize icons
587
+ if (window.lucide) lucide.createIcons();
588
+ }
589
+
590
+ function buildFileBrowserModalContent() {
591
+ // Detect if Windows
592
+ var isWindows = navigator.platform.indexOf('Win') > -1;
593
+ var driveButtons = '';
594
+ if (isWindows) {
595
+ driveButtons = '<div class="file-browser-drives">' +
596
+ '<button class="btn-xs btn-outline drive-btn" data-drive="C:/">C:</button>' +
597
+ '<button class="btn-xs btn-outline drive-btn" data-drive="D:/">D:</button>' +
598
+ '<button class="btn-xs btn-outline drive-btn" data-drive="E:/">E:</button>' +
599
+ '</div>';
600
+ }
601
+
602
+ return '<div class="modal-content file-browser-modal">' +
603
+ '<div class="modal-header">' +
604
+ '<h3><i data-lucide="folder-open" class="w-4 h-4"></i> ' + t('cli.fileBrowser') + '</h3>' +
605
+ '<button class="modal-close" id="fileBrowserCloseBtn">&times;</button>' +
606
+ '</div>' +
607
+ '<div class="modal-body">' +
608
+ '<div class="file-browser-toolbar">' +
609
+ '<button class="btn-sm btn-outline" id="fileBrowserUpBtn" title="' + t('cli.fileBrowserUp') + '">' +
610
+ '<i data-lucide="arrow-up" class="w-3.5 h-3.5"></i>' +
611
+ '</button>' +
612
+ '<button class="btn-sm btn-outline" id="fileBrowserHomeBtn" title="' + t('cli.fileBrowserHome') + '">' +
613
+ '<i data-lucide="home" class="w-3.5 h-3.5"></i>' +
614
+ '</button>' +
615
+ driveButtons +
616
+ '<input type="text" id="fileBrowserPathInput" class="file-browser-path" placeholder="Enter path and press Enter" />' +
617
+ '<label class="file-browser-hidden-toggle">' +
618
+ '<input type="checkbox" id="fileBrowserShowHidden" checked />' +
619
+ '<span>' + t('cli.fileBrowserShowHidden') + '</span>' +
620
+ '</label>' +
621
+ '</div>' +
622
+ '<div class="file-browser-list" id="fileBrowserList">' +
623
+ '<div class="file-browser-loading"><i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i></div>' +
624
+ '</div>' +
625
+ '</div>' +
626
+ '<div class="modal-footer">' +
627
+ '<button class="btn btn-outline" id="fileBrowserCancelBtn">' + t('cli.fileBrowserCancel') + '</button>' +
628
+ '<button class="btn btn-primary" id="fileBrowserSelectBtn" disabled>' +
629
+ '<i data-lucide="check" class="w-3.5 h-3.5"></i> ' + t('cli.fileBrowserSelect') +
630
+ '</button>' +
631
+ '</div>' +
632
+ '</div>';
633
+ }
634
+
635
+ async function loadFileBrowserDirectory(path) {
636
+ var listContainer = document.getElementById('fileBrowserList');
637
+ var pathInput = document.getElementById('fileBrowserPathInput');
638
+
639
+ if (listContainer) {
640
+ listContainer.innerHTML = '<div class="file-browser-loading"><i data-lucide="loader-2" class="w-5 h-5 animate-spin"></i></div>';
641
+ if (window.lucide) lucide.createIcons();
642
+ }
643
+
644
+ try {
645
+ var response = await fetch('/api/dialog/browse', {
646
+ method: 'POST',
647
+ headers: { 'Content-Type': 'application/json' },
648
+ body: JSON.stringify({ path: path, showHidden: fileBrowserState.showHidden })
649
+ });
650
+
651
+ if (!response.ok) {
652
+ throw new Error('Failed to load directory');
653
+ }
654
+
655
+ var data = await response.json();
656
+ fileBrowserState.currentPath = data.currentPath;
657
+
658
+ if (pathInput) {
659
+ pathInput.value = data.currentPath;
660
+ }
661
+
662
+ renderFileBrowserItems(data.items);
663
+ } catch (err) {
664
+ console.error('Failed to load directory:', err);
665
+ if (listContainer) {
666
+ listContainer.innerHTML = '<div class="file-browser-error">' +
667
+ '<p>' + t('cli.fileBrowserApiError') + '</p>' +
668
+ '<p class="file-browser-hint">' + t('cli.fileBrowserManualHint') + '</p>' +
669
+ '</div>';
670
+ }
671
+ // Enable manual path entry mode - enable select button when path is typed
672
+ var selectBtn = document.getElementById('fileBrowserSelectBtn');
673
+ var pathInput = document.getElementById('fileBrowserPathInput');
674
+ if (selectBtn && pathInput) {
675
+ selectBtn.disabled = false;
676
+ pathInput.focus();
677
+ }
678
+ }
679
+ }
680
+
681
+ function renderFileBrowserItems(items) {
682
+ var listContainer = document.getElementById('fileBrowserList');
683
+ if (!listContainer) return;
684
+
685
+ if (!items || items.length === 0) {
686
+ listContainer.innerHTML = '<div class="file-browser-empty">Empty directory</div>';
687
+ return;
688
+ }
689
+
690
+ var html = items.map(function(item) {
691
+ var icon = item.isDirectory ? 'folder' : 'file';
692
+ var itemClass = 'file-browser-item' + (item.isDirectory ? ' is-directory' : ' is-file');
693
+ return '<div class="' + itemClass + '" data-path="' + escapeHtml(item.path) + '" data-is-dir="' + item.isDirectory + '">' +
694
+ '<i data-lucide="' + icon + '" class="w-4 h-4"></i>' +
695
+ '<span class="file-browser-item-name">' + escapeHtml(item.name) + '</span>' +
696
+ '</div>';
697
+ }).join('');
698
+
699
+ listContainer.innerHTML = html;
700
+
701
+ // Initialize icons
702
+ if (window.lucide) lucide.createIcons();
703
+
704
+ // Add click handlers
705
+ listContainer.querySelectorAll('.file-browser-item').forEach(function(el) {
706
+ el.onclick = function() {
707
+ var isDir = el.getAttribute('data-is-dir') === 'true';
708
+ var path = el.getAttribute('data-path');
709
+
710
+ if (isDir) {
711
+ // Navigate into directory
712
+ loadFileBrowserDirectory(path);
713
+ } else {
714
+ // Select file
715
+ listContainer.querySelectorAll('.file-browser-item').forEach(function(item) {
716
+ item.classList.remove('selected');
717
+ });
718
+ el.classList.add('selected');
719
+
720
+ // Enable select button
721
+ var selectBtn = document.getElementById('fileBrowserSelectBtn');
722
+ if (selectBtn) {
723
+ selectBtn.disabled = false;
724
+ selectBtn.setAttribute('data-selected-path', path);
725
+ }
726
+ }
727
+ };
728
+
729
+ // Double-click to select file or enter directory
730
+ el.ondblclick = function() {
731
+ var isDir = el.getAttribute('data-is-dir') === 'true';
732
+ var path = el.getAttribute('data-path');
733
+
734
+ if (isDir) {
735
+ loadFileBrowserDirectory(path);
736
+ } else {
737
+ // Select and close
738
+ closeFileBrowserModal(path);
739
+ }
740
+ };
741
+ });
742
+ }
743
+
744
+ function initFileBrowserEvents() {
745
+ // Close button
746
+ var closeBtn = document.getElementById('fileBrowserCloseBtn');
747
+ if (closeBtn) {
748
+ closeBtn.onclick = function() { closeFileBrowserModal(null); };
749
+ }
750
+
751
+ // Cancel button
752
+ var cancelBtn = document.getElementById('fileBrowserCancelBtn');
753
+ if (cancelBtn) {
754
+ cancelBtn.onclick = function() { closeFileBrowserModal(null); };
755
+ }
756
+
757
+ // Select button
758
+ var selectBtn = document.getElementById('fileBrowserSelectBtn');
759
+ if (selectBtn) {
760
+ selectBtn.onclick = function() {
761
+ // First try selected path from list, then fall back to path input
762
+ var path = selectBtn.getAttribute('data-selected-path');
763
+ if (!path) {
764
+ var pathInput = document.getElementById('fileBrowserPathInput');
765
+ if (pathInput && pathInput.value.trim()) {
766
+ path = pathInput.value.trim();
767
+ }
768
+ }
769
+ if (path) {
770
+ closeFileBrowserModal(path);
771
+ }
772
+ };
773
+ }
774
+
775
+ // Up button
776
+ var upBtn = document.getElementById('fileBrowserUpBtn');
777
+ if (upBtn) {
778
+ upBtn.onclick = function() {
779
+ // Get parent path
780
+ var currentPath = fileBrowserState.currentPath;
781
+ var parentPath = currentPath.replace(/[/\\][^/\\]+$/, '') || '/';
782
+ loadFileBrowserDirectory(parentPath);
783
+ };
784
+ }
785
+
786
+ // Home button
787
+ var homeBtn = document.getElementById('fileBrowserHomeBtn');
788
+ if (homeBtn) {
789
+ homeBtn.onclick = function() {
790
+ loadFileBrowserDirectory('');
791
+ };
792
+ }
793
+
794
+ // Drive buttons (Windows)
795
+ document.querySelectorAll('.drive-btn').forEach(function(btn) {
796
+ btn.onclick = function() {
797
+ var drive = btn.getAttribute('data-drive');
798
+ if (drive) {
799
+ loadFileBrowserDirectory(drive);
800
+ }
801
+ };
802
+ });
803
+
804
+ // Path input - allow manual entry
805
+ var pathInput = document.getElementById('fileBrowserPathInput');
806
+ if (pathInput) {
807
+ pathInput.onkeydown = function(e) {
808
+ if (e.key === 'Enter') {
809
+ e.preventDefault();
810
+ var path = pathInput.value.trim();
811
+ if (path) {
812
+ loadFileBrowserDirectory(path);
813
+ }
814
+ }
815
+ };
816
+ }
817
+
818
+ // Show hidden checkbox
819
+ var showHiddenCheckbox = document.getElementById('fileBrowserShowHidden');
820
+ if (showHiddenCheckbox) {
821
+ showHiddenCheckbox.checked = true; // Default to show hidden
822
+ fileBrowserState.showHidden = true;
823
+ showHiddenCheckbox.onchange = function() {
824
+ fileBrowserState.showHidden = showHiddenCheckbox.checked;
825
+ loadFileBrowserDirectory(fileBrowserState.currentPath);
826
+ };
827
+ }
828
+
829
+ // Click outside to close
830
+ var overlay = document.getElementById('fileBrowserOverlay');
831
+ if (overlay) {
832
+ overlay.onclick = function(e) {
833
+ if (e.target === overlay) {
834
+ closeFileBrowserModal(null);
835
+ }
836
+ };
837
+ }
838
+ }
839
+
840
+ function closeFileBrowserModal(selectedPath) {
841
+ var overlay = document.getElementById('fileBrowserOverlay');
842
+ if (overlay) {
843
+ overlay.remove();
844
+ }
845
+
846
+ if (fileBrowserState.onSelect && selectedPath) {
847
+ fileBrowserState.onSelect(selectedPath);
848
+ }
849
+
850
+ fileBrowserState.onSelect = null;
851
+ }
852
+
557
853
  function initToolConfigModalEvents(tool, currentConfig, models) {
558
854
  // Local tags state (copy from config)
559
855
  var currentTags = (currentConfig.tags || []).slice();
@@ -754,38 +1050,14 @@ function initToolConfigModalEvents(tool, currentConfig, models) {
754
1050
  // Environment file browse button (only for gemini/qwen)
755
1051
  var envFileBrowseBtn = document.getElementById('envFileBrowseBtn');
756
1052
  if (envFileBrowseBtn) {
757
- envFileBrowseBtn.onclick = async function() {
758
- try {
759
- // Use file dialog API if available
760
- var response = await fetch('/api/dialog/open-file', {
761
- method: 'POST',
762
- headers: { 'Content-Type': 'application/json' },
763
- body: JSON.stringify({
764
- title: t('cli.envFile'),
765
- filters: [
766
- { name: 'Environment Files', extensions: ['env'] },
767
- { name: 'All Files', extensions: ['*'] }
768
- ],
769
- defaultPath: ''
770
- })
771
- });
772
-
773
- if (response.ok) {
774
- var data = await response.json();
775
- if (data.filePath) {
776
- var envFileInput = document.getElementById('envFileInput');
777
- if (envFileInput) {
778
- envFileInput.value = data.filePath;
779
- }
780
- }
781
- } else {
782
- // Fallback: prompt user to enter path manually
783
- showRefreshToast('File dialog not available. Please enter path manually.', 'info');
1053
+ envFileBrowseBtn.onclick = function() {
1054
+ showFileBrowserModal(function(selectedPath) {
1055
+ var envFileInput = document.getElementById('envFileInput');
1056
+ if (envFileInput && selectedPath) {
1057
+ envFileInput.value = selectedPath;
1058
+ envFileInput.focus();
784
1059
  }
785
- } catch (err) {
786
- console.error('Failed to open file dialog:', err);
787
- showRefreshToast('File dialog not available. Please enter path manually.', 'info');
788
- }
1060
+ });
789
1061
  };
790
1062
  }
791
1063
 
@@ -7,6 +7,9 @@ var isMultiSelectMode = false;
7
7
 
8
8
  // ========== Rendering ==========
9
9
  async function renderCliHistoryView() {
10
+ // Reset view state to prevent stale data persistence
11
+ resetHistoryViewState();
12
+
10
13
  var container = document.getElementById('mainContent');
11
14
  if (!container) return;
12
15
 
@@ -183,6 +186,9 @@ async function renderCliHistoryView() {
183
186
  if (window.lucide) lucide.createIcons();
184
187
  }
185
188
 
189
+ // Export destroy function for lifecycle management
190
+ window.destroyCliHistoryView = destroyCliHistoryView;
191
+
186
192
  // ========== Actions ==========
187
193
  async function copyExecutionId(executionId) {
188
194
  try {
@@ -218,16 +224,28 @@ async function refreshCliHistoryView() {
218
224
  }
219
225
 
220
226
  // ========== Multi-Select Functions ==========
227
+ var deleteDropdownListenerActive = false;
228
+
221
229
  function toggleDeleteDropdown(event) {
222
230
  event.stopPropagation();
223
231
  var menu = document.getElementById('deleteDropdownMenu');
224
232
  if (menu) {
225
- menu.classList.toggle('show');
226
- // Close on outside click
227
233
  if (menu.classList.contains('show')) {
228
- setTimeout(function() {
229
- document.addEventListener('click', closeDeleteDropdown);
230
- }, 0);
234
+ // Closing: remove listener if active
235
+ menu.classList.remove('show');
236
+ if (deleteDropdownListenerActive) {
237
+ document.removeEventListener('click', closeDeleteDropdown);
238
+ deleteDropdownListenerActive = false;
239
+ }
240
+ } else {
241
+ // Opening: add listener if not already active
242
+ menu.classList.add('show');
243
+ if (!deleteDropdownListenerActive) {
244
+ setTimeout(function() {
245
+ document.addEventListener('click', closeDeleteDropdown);
246
+ deleteDropdownListenerActive = true;
247
+ }, 0);
248
+ }
231
249
  }
232
250
  }
233
251
  }
@@ -235,7 +253,10 @@ function toggleDeleteDropdown(event) {
235
253
  function closeDeleteDropdown() {
236
254
  var menu = document.getElementById('deleteDropdownMenu');
237
255
  if (menu) menu.classList.remove('show');
238
- document.removeEventListener('click', closeDeleteDropdown);
256
+ if (deleteDropdownListenerActive) {
257
+ document.removeEventListener('click', closeDeleteDropdown);
258
+ deleteDropdownListenerActive = false;
259
+ }
239
260
  }
240
261
 
241
262
  function enterMultiSelectMode() {
@@ -279,6 +300,23 @@ function clearExecutionSelection() {
279
300
  renderCliHistoryView();
280
301
  }
281
302
 
303
+ function resetHistoryViewState() {
304
+ selectedExecutions.clear();
305
+ isMultiSelectMode = false;
306
+ }
307
+
308
+ // ========== View Lifecycle ==========
309
+ function destroyCliHistoryView() {
310
+ // Clean up dropdown listener if active
311
+ if (deleteDropdownListenerActive) {
312
+ document.removeEventListener('click', closeDeleteDropdown);
313
+ deleteDropdownListenerActive = false;
314
+ }
315
+ // Ensure dropdown menu is closed
316
+ var menu = document.getElementById('deleteDropdownMenu');
317
+ if (menu) menu.classList.remove('show');
318
+ }
319
+
282
320
  // ========== Batch Delete Functions ==========
283
321
  function confirmBatchDelete() {
284
322
  var count = selectedExecutions.size;
@@ -51,6 +51,7 @@ function updateBadges() {
51
51
  const liteTasks = workflowData.liteTasks || {};
52
52
  document.getElementById('badgeLitePlan').textContent = liteTasks.litePlan?.length || 0;
53
53
  document.getElementById('badgeLiteFix').textContent = liteTasks.liteFix?.length || 0;
54
+ document.getElementById('badgeMultiCliPlan').textContent = liteTasks.multiCliPlan?.length || 0;
54
55
 
55
56
  // MCP badge - load async if needed
56
57
  if (typeof loadMcpConfig === 'function') {
@@ -6,6 +6,7 @@
6
6
  // ========== Issue State ==========
7
7
  var issueData = {
8
8
  issues: [],
9
+ historyIssues: [], // Archived/completed issues from history
9
10
  queue: { tasks: [], solutions: [], conflicts: [], execution_groups: [], grouped_items: {} },
10
11
  selectedIssue: null,
11
12
  selectedSolution: null,
@@ -58,6 +59,18 @@ async function loadIssueData() {
58
59
  }
59
60
  }
60
61
 
62
+ async function loadIssueHistory() {
63
+ try {
64
+ const response = await fetch('/api/issues/history?path=' + encodeURIComponent(projectPath));
65
+ if (!response.ok) throw new Error('Failed to load issue history');
66
+ const data = await response.json();
67
+ issueData.historyIssues = data.issues || [];
68
+ } catch (err) {
69
+ console.error('Failed to load issue history:', err);
70
+ issueData.historyIssues = [];
71
+ }
72
+ }
73
+
61
74
  async function loadQueueData() {
62
75
  try {
63
76
  const response = await fetch('/api/queue?path=' + encodeURIComponent(projectPath));
@@ -93,10 +106,21 @@ function renderIssueView() {
93
106
  if (!container) return;
94
107
 
95
108
  const issues = issueData.issues || [];
109
+ const historyIssues = issueData.historyIssues || [];
110
+
96
111
  // Apply both status and search filters
97
- let filteredIssues = issueData.statusFilter === 'all'
98
- ? issues
99
- : issues.filter(i => i.status === issueData.statusFilter);
112
+ let filteredIssues;
113
+ if (issueData.statusFilter === 'all') {
114
+ filteredIssues = issues;
115
+ } else if (issueData.statusFilter === 'completed') {
116
+ // For 'completed' filter, include both current completed issues and archived history issues
117
+ const currentCompleted = issues.filter(i => i.status === 'completed');
118
+ // Mark history issues as archived for visual distinction
119
+ const archivedIssues = historyIssues.map(i => ({ ...i, _isArchived: true }));
120
+ filteredIssues = [...currentCompleted, ...archivedIssues];
121
+ } else {
122
+ filteredIssues = issues.filter(i => i.status === issueData.statusFilter);
123
+ }
100
124
 
101
125
  if (issueData.searchQuery) {
102
126
  const query = issueData.searchQuery.toLowerCase();
@@ -309,12 +333,15 @@ function renderIssueCard(issue) {
309
333
  failed: 'failed'
310
334
  };
311
335
 
336
+ const isArchived = issue._isArchived;
337
+
312
338
  return `
313
- <div class="issue-card" onclick="openIssueDetail('${issue.id}')">
339
+ <div class="issue-card ${isArchived ? 'archived' : ''}" onclick="openIssueDetail('${issue.id}'${isArchived ? ', true' : ''})">
314
340
  <div class="flex items-start justify-between mb-3">
315
341
  <div class="flex items-center gap-2">
316
342
  <span class="issue-id font-mono text-sm">${issue.id}</span>
317
343
  <span class="issue-status ${statusColors[issue.status] || ''}">${issue.status || 'unknown'}</span>
344
+ ${isArchived ? '<span class="issue-archived-badge">' + (t('issues.archived') || 'Archived') + '</span>' : ''}
318
345
  </div>
319
346
  <span class="issue-priority" title="${t('issues.priority') || 'Priority'}: ${issue.priority || 3}">
320
347
  ${renderPriorityStars(issue.priority || 3)}
@@ -360,8 +387,12 @@ function renderPriorityStars(priority) {
360
387
  return stars;
361
388
  }
362
389
 
363
- function filterIssuesByStatus(status) {
390
+ async function filterIssuesByStatus(status) {
364
391
  issueData.statusFilter = status;
392
+ // Load history data when filtering by 'completed' status
393
+ if (status === 'completed' && issueData.historyIssues.length === 0) {
394
+ await loadIssueHistory();
395
+ }
365
396
  renderIssueView();
366
397
  }
367
398
 
@@ -725,7 +756,7 @@ async function saveQueueOrder(groupId, newOrder) {
725
756
  }
726
757
 
727
758
  // ========== Detail Panel ==========
728
- async function openIssueDetail(issueId) {
759
+ async function openIssueDetail(issueId, isArchived = false) {
729
760
  const panel = document.getElementById('issueDetailPanel');
730
761
  if (!panel) return;
731
762
 
@@ -733,7 +764,23 @@ async function openIssueDetail(issueId) {
733
764
  panel.classList.remove('hidden');
734
765
  lucide.createIcons();
735
766
 
736
- const detail = await loadIssueDetail(issueId);
767
+ let detail;
768
+ if (isArchived) {
769
+ // For archived issues, get detail from historyIssues (already loaded)
770
+ const historyIssue = issueData.historyIssues.find(i => i.id === issueId);
771
+ if (historyIssue) {
772
+ // Mark as archived and provide minimal detail structure
773
+ detail = {
774
+ ...historyIssue,
775
+ _isArchived: true,
776
+ solutions: historyIssue.solutions || [],
777
+ tasks: historyIssue.tasks || []
778
+ };
779
+ }
780
+ } else {
781
+ detail = await loadIssueDetail(issueId);
782
+ }
783
+
737
784
  if (!detail) {
738
785
  panel.innerHTML = '<div class="p-8 text-center text-destructive">Failed to load issue</div>';
739
786
  return;