claude-code-workflow 6.3.27 → 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.
- package/.claude/CLAUDE.md +7 -1
- package/.claude/agents/action-planning-agent.md +1 -0
- package/.claude/agents/cli-discuss-agent.md +391 -0
- package/.claude/agents/cli-execution-agent.md +2 -0
- package/.claude/agents/cli-explore-agent.md +2 -1
- package/.claude/agents/cli-lite-planning-agent.md +1 -0
- package/.claude/agents/cli-planning-agent.md +1 -0
- package/.claude/agents/code-developer.md +1 -0
- package/.claude/agents/conceptual-planning-agent.md +2 -0
- package/.claude/agents/context-search-agent.md +1 -0
- package/.claude/agents/debug-explore-agent.md +2 -0
- package/.claude/agents/doc-generator.md +1 -0
- package/.claude/agents/issue-plan-agent.md +2 -1
- package/.claude/agents/issue-queue-agent.md +2 -1
- package/.claude/agents/memory-bridge.md +2 -0
- package/.claude/agents/test-context-search-agent.md +2 -0
- package/.claude/agents/test-fix-agent.md +1 -0
- package/.claude/agents/ui-design-agent.md +2 -0
- package/.claude/agents/universal-executor.md +1 -0
- package/.claude/commands/issue/execute.md +141 -163
- package/.claude/commands/workflow/lite-lite-lite.md +798 -0
- package/.claude/commands/workflow/multi-cli-plan.md +510 -0
- package/.claude/skills/ccw/SKILL.md +262 -372
- package/.claude/skills/ccw/command.json +547 -0
- package/.claude/skills/ccw-help/SKILL.md +46 -107
- package/.claude/skills/ccw-help/command.json +511 -0
- package/.claude/skills/skill-tuning/SKILL.md +303 -0
- package/.claude/skills/skill-tuning/phases/actions/action-abort.md +164 -0
- package/.claude/skills/skill-tuning/phases/actions/action-analyze-requirements.md +406 -0
- package/.claude/skills/skill-tuning/phases/actions/action-apply-fix.md +206 -0
- package/.claude/skills/skill-tuning/phases/actions/action-complete.md +195 -0
- package/.claude/skills/skill-tuning/phases/actions/action-diagnose-agent.md +317 -0
- package/.claude/skills/skill-tuning/phases/actions/action-diagnose-context.md +243 -0
- package/.claude/skills/skill-tuning/phases/actions/action-diagnose-dataflow.md +318 -0
- package/.claude/skills/skill-tuning/phases/actions/action-diagnose-docs.md +299 -0
- package/.claude/skills/skill-tuning/phases/actions/action-diagnose-memory.md +269 -0
- package/.claude/skills/skill-tuning/phases/actions/action-diagnose-token-consumption.md +200 -0
- package/.claude/skills/skill-tuning/phases/actions/action-gemini-analysis.md +322 -0
- package/.claude/skills/skill-tuning/phases/actions/action-generate-report.md +228 -0
- package/.claude/skills/skill-tuning/phases/actions/action-init.md +149 -0
- package/.claude/skills/skill-tuning/phases/actions/action-propose-fixes.md +317 -0
- package/.claude/skills/skill-tuning/phases/actions/action-verify.md +222 -0
- package/.claude/skills/skill-tuning/phases/orchestrator.md +377 -0
- package/.claude/skills/skill-tuning/phases/state-schema.md +378 -0
- package/.claude/skills/skill-tuning/specs/category-mappings.json +284 -0
- package/.claude/skills/skill-tuning/specs/dimension-mapping.md +212 -0
- package/.claude/skills/skill-tuning/specs/problem-taxonomy.md +318 -0
- package/.claude/skills/skill-tuning/specs/quality-gates.md +263 -0
- package/.claude/skills/skill-tuning/specs/skill-authoring-principles.md +189 -0
- package/.claude/skills/skill-tuning/specs/tuning-strategies.md +1537 -0
- package/.claude/skills/skill-tuning/templates/diagnosis-report.md +153 -0
- package/.claude/skills/skill-tuning/templates/fix-proposal.md +204 -0
- package/.claude/workflows/cli-templates/schemas/multi-cli-discussion-schema.json +421 -0
- package/.claude/workflows/cli-tools-usage.md +0 -41
- package/ccw/dist/core/data-aggregator.d.ts +2 -0
- package/ccw/dist/core/data-aggregator.d.ts.map +1 -1
- package/ccw/dist/core/data-aggregator.js +5 -2
- package/ccw/dist/core/data-aggregator.js.map +1 -1
- package/ccw/dist/core/lite-scanner.d.ts +2 -1
- package/ccw/dist/core/lite-scanner.d.ts.map +1 -1
- package/ccw/dist/core/lite-scanner.js +295 -6
- package/ccw/dist/core/lite-scanner.js.map +1 -1
- package/ccw/dist/core/routes/session-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/session-routes.js +166 -48
- package/ccw/dist/core/routes/session-routes.js.map +1 -1
- package/ccw/dist/core/routes/system-routes.d.ts.map +1 -1
- package/ccw/dist/core/routes/system-routes.js +87 -0
- package/ccw/dist/core/routes/system-routes.js.map +1 -1
- package/ccw/dist/core/server.js +2 -2
- package/ccw/dist/core/server.js.map +1 -1
- package/ccw/scripts/IMPLEMENTATION-SUMMARY.md +226 -0
- package/ccw/scripts/QUICK-REFERENCE.md +135 -0
- package/ccw/scripts/README-memory-embedder.md +157 -0
- package/ccw/scripts/__pycache__/memory_embedder.cpython-313.pyc +0 -0
- package/ccw/scripts/__pycache__/test_memory_embedder.cpython-313-pytest-8.4.2.pyc +0 -0
- package/ccw/scripts/memory-embedder-example.ts +184 -0
- package/ccw/scripts/memory_embedder.py +428 -0
- package/ccw/scripts/test_memory_embedder.py +245 -0
- package/ccw/src/core/data-aggregator.ts +7 -2
- package/ccw/src/core/lite-scanner.ts +440 -6
- package/ccw/src/core/routes/session-routes.ts +201 -48
- package/ccw/src/core/routes/system-routes.ts +102 -0
- package/ccw/src/core/server.ts +2 -2
- package/ccw/src/templates/dashboard-css/01-base.css +8 -0
- package/ccw/src/templates/dashboard-css/02-session.css +81 -0
- package/ccw/src/templates/dashboard-css/04-lite-tasks.css +2442 -0
- package/ccw/src/templates/dashboard-css/21-cli-toolmgmt.css +157 -0
- package/ccw/src/templates/dashboard-css/32-issue-manager.css +23 -0
- package/ccw/src/templates/dashboard-js/components/cli-stream-viewer.js +38 -4
- package/ccw/src/templates/dashboard-js/components/hook-manager.js +38 -13
- package/ccw/src/templates/dashboard-js/components/navigation.js +24 -4
- package/ccw/src/templates/dashboard-js/i18n.js +178 -4
- package/ccw/src/templates/dashboard-js/views/api-settings.js +32 -0
- package/ccw/src/templates/dashboard-js/views/claude-manager.js +44 -3
- package/ccw/src/templates/dashboard-js/views/cli-manager.js +303 -31
- package/ccw/src/templates/dashboard-js/views/history.js +44 -6
- package/ccw/src/templates/dashboard-js/views/home.js +1 -0
- package/ccw/src/templates/dashboard-js/views/issue-manager.js +54 -7
- package/ccw/src/templates/dashboard-js/views/lite-tasks.js +1817 -4
- package/ccw/src/templates/dashboard.html +5 -0
- package/package.json +2 -1
- package/.claude/skills/ccw/index/command-capabilities.json +0 -127
- package/.claude/skills/ccw/index/intent-rules.json +0 -136
- package/.claude/skills/ccw/index/workflow-chains.json +0 -451
- package/.claude/skills/ccw/phases/actions/bugfix.md +0 -218
- package/.claude/skills/ccw/phases/actions/coupled.md +0 -194
- package/.claude/skills/ccw/phases/actions/docs.md +0 -93
- package/.claude/skills/ccw/phases/actions/full.md +0 -154
- package/.claude/skills/ccw/phases/actions/issue.md +0 -201
- package/.claude/skills/ccw/phases/actions/rapid.md +0 -104
- package/.claude/skills/ccw/phases/actions/review-fix.md +0 -84
- package/.claude/skills/ccw/phases/actions/tdd.md +0 -66
- package/.claude/skills/ccw/phases/actions/ui.md +0 -79
- package/.claude/skills/ccw/phases/orchestrator.md +0 -435
- package/.claude/skills/ccw/specs/intent-classification.md +0 -336
- package/.claude/skills/ccw-help/index/all-agents.json +0 -82
- package/.claude/skills/ccw-help/index/all-commands.json +0 -882
- package/.claude/skills/ccw-help/index/by-category.json +0 -914
- package/.claude/skills/ccw-help/index/by-use-case.json +0 -896
- package/.claude/skills/ccw-help/index/command-relationships.json +0 -160
- package/.claude/skills/ccw-help/index/essential-commands.json +0 -112
|
@@ -216,6 +216,11 @@ async function saveCliSettingsEndpoint(data) {
|
|
|
216
216
|
const result = await response.json();
|
|
217
217
|
showRefreshToast(t('apiSettings.settingsSaved'), 'success');
|
|
218
218
|
|
|
219
|
+
// Invalidate cache to ensure fresh data on page refresh
|
|
220
|
+
if (window.cacheManager) {
|
|
221
|
+
window.cacheManager.invalidate('cli-wrapper-endpoints');
|
|
222
|
+
}
|
|
223
|
+
|
|
219
224
|
// Refresh data and re-render
|
|
220
225
|
await loadCliSettings(true);
|
|
221
226
|
renderCliSettingsList();
|
|
@@ -250,6 +255,11 @@ async function deleteCliSettingsEndpoint(endpointId) {
|
|
|
250
255
|
|
|
251
256
|
showRefreshToast(t('apiSettings.settingsDeleted'), 'success');
|
|
252
257
|
|
|
258
|
+
// Invalidate cache to ensure fresh data on page refresh
|
|
259
|
+
if (window.cacheManager) {
|
|
260
|
+
window.cacheManager.invalidate('cli-wrapper-endpoints');
|
|
261
|
+
}
|
|
262
|
+
|
|
253
263
|
// Refresh data and re-render
|
|
254
264
|
await loadCliSettings(true);
|
|
255
265
|
selectedCliSettingsId = null;
|
|
@@ -635,6 +645,11 @@ async function saveProvider() {
|
|
|
635
645
|
const result = await response.json();
|
|
636
646
|
showRefreshToast(t('apiSettings.providerSaved'), 'success');
|
|
637
647
|
|
|
648
|
+
// Invalidate cache to ensure fresh data on page refresh
|
|
649
|
+
if (window.cacheManager) {
|
|
650
|
+
window.cacheManager.invalidate('cli-litellm-endpoints');
|
|
651
|
+
}
|
|
652
|
+
|
|
638
653
|
closeProviderModal();
|
|
639
654
|
// Force refresh data after saving
|
|
640
655
|
apiSettingsData = null;
|
|
@@ -660,6 +675,12 @@ async function deleteProvider(providerId) {
|
|
|
660
675
|
if (!response.ok) throw new Error('Failed to delete provider');
|
|
661
676
|
|
|
662
677
|
showRefreshToast(t('apiSettings.providerDeleted'), 'success');
|
|
678
|
+
|
|
679
|
+
// Invalidate cache to ensure fresh data on page refresh
|
|
680
|
+
if (window.cacheManager) {
|
|
681
|
+
window.cacheManager.invalidate('cli-litellm-endpoints');
|
|
682
|
+
}
|
|
683
|
+
|
|
663
684
|
// Force refresh data after deleting
|
|
664
685
|
apiSettingsData = null;
|
|
665
686
|
await renderApiSettings();
|
|
@@ -998,6 +1019,11 @@ async function saveEndpoint() {
|
|
|
998
1019
|
const result = await response.json();
|
|
999
1020
|
showRefreshToast(t('apiSettings.endpointSaved'), 'success');
|
|
1000
1021
|
|
|
1022
|
+
// Invalidate cache to ensure fresh data on page refresh
|
|
1023
|
+
if (window.cacheManager) {
|
|
1024
|
+
window.cacheManager.invalidate('cli-litellm-endpoints');
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1001
1027
|
closeEndpointModal();
|
|
1002
1028
|
// Force refresh data after saving
|
|
1003
1029
|
apiSettingsData = null;
|
|
@@ -1023,6 +1049,12 @@ async function deleteEndpoint(endpointId) {
|
|
|
1023
1049
|
if (!response.ok) throw new Error('Failed to delete endpoint');
|
|
1024
1050
|
|
|
1025
1051
|
showRefreshToast(t('apiSettings.endpointDeleted'), 'success');
|
|
1052
|
+
|
|
1053
|
+
// Invalidate cache to ensure fresh data on page refresh
|
|
1054
|
+
if (window.cacheManager) {
|
|
1055
|
+
window.cacheManager.invalidate('cli-litellm-endpoints');
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1026
1058
|
// Force refresh data after deleting
|
|
1027
1059
|
apiSettingsData = null;
|
|
1028
1060
|
await renderApiSettings();
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
// CLAUDE.md Manager View
|
|
2
2
|
// Three-column layout: File Tree | Viewer/Editor | Metadata & Actions
|
|
3
3
|
|
|
4
|
+
// ========== Lifecycle Management ==========
|
|
5
|
+
var claudeManagerDestroy = null;
|
|
6
|
+
var createDialogOverlay = null; // Track create dialog overlay for cleanup
|
|
7
|
+
|
|
4
8
|
// ========== State Management ==========
|
|
5
9
|
var claudeFilesData = {
|
|
6
10
|
user: { main: null },
|
|
@@ -19,9 +23,15 @@ var fileTreeExpanded = {
|
|
|
19
23
|
var searchQuery = '';
|
|
20
24
|
var freshnessData = {}; // { [filePath]: FreshnessResult }
|
|
21
25
|
var freshnessSummary = null;
|
|
26
|
+
var searchKeyboardHandlerAdded = false;
|
|
22
27
|
|
|
23
28
|
// ========== Main Render Function ==========
|
|
24
29
|
async function renderClaudeManager() {
|
|
30
|
+
// Initialize lifecycle
|
|
31
|
+
if (typeof initClaudeManager === 'function') {
|
|
32
|
+
initClaudeManager();
|
|
33
|
+
}
|
|
34
|
+
|
|
25
35
|
var container = document.getElementById('mainContent');
|
|
26
36
|
if (!container) return;
|
|
27
37
|
|
|
@@ -749,9 +759,11 @@ function filterFileTree(query) {
|
|
|
749
759
|
renderFileTree();
|
|
750
760
|
|
|
751
761
|
// Add keyboard shortcut handler
|
|
752
|
-
if (query && !
|
|
753
|
-
|
|
754
|
-
|
|
762
|
+
if (query && !searchKeyboardHandlerAdded) {
|
|
763
|
+
(function() {
|
|
764
|
+
document.addEventListener('keydown', handleSearchKeyboard);
|
|
765
|
+
searchKeyboardHandlerAdded = true;
|
|
766
|
+
})();
|
|
755
767
|
}
|
|
756
768
|
}
|
|
757
769
|
|
|
@@ -796,6 +808,7 @@ function showCreateFileDialog() {
|
|
|
796
808
|
'</div>';
|
|
797
809
|
|
|
798
810
|
document.body.insertAdjacentHTML('beforeend', dialog);
|
|
811
|
+
createDialogOverlay = document.querySelector('.modal-overlay');
|
|
799
812
|
if (window.lucide) lucide.createIcons();
|
|
800
813
|
}
|
|
801
814
|
|
|
@@ -918,3 +931,31 @@ function updateClaudeBadge() {
|
|
|
918
931
|
badge.textContent = total;
|
|
919
932
|
}
|
|
920
933
|
}
|
|
934
|
+
|
|
935
|
+
// ========== Lifecycle Functions ==========
|
|
936
|
+
function destroyClaudeManager() {
|
|
937
|
+
// Remove search keyboard event listener if added
|
|
938
|
+
if (searchKeyboardHandlerAdded) {
|
|
939
|
+
document.removeEventListener('keydown', handleSearchKeyboard);
|
|
940
|
+
searchKeyboardHandlerAdded = false;
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
// Remove create dialog overlay if exists
|
|
944
|
+
if (createDialogOverlay) {
|
|
945
|
+
createDialogOverlay.remove();
|
|
946
|
+
createDialogOverlay = null;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
// Reset view-specific state
|
|
950
|
+
selectedFile = null;
|
|
951
|
+
isEditMode = false;
|
|
952
|
+
isDirty = false;
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
// Expose init/destroy functions for lifecycle management
|
|
956
|
+
window.initClaudeManager = function() {
|
|
957
|
+
claudeManagerDestroy = destroyClaudeManager;
|
|
958
|
+
};
|
|
959
|
+
|
|
960
|
+
// Make destroyClaudeManager accessible globally as well
|
|
961
|
+
window.destroyClaudeManager = destroyClaudeManager;
|
|
@@ -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">×</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 =
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
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
|
-
}
|
|
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
|
-
|
|
229
|
-
|
|
230
|
-
|
|
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
|
-
|
|
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') {
|