claude-code-workflow 7.2.28 → 7.2.29
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/.codex/skills/brainstorm/SKILL.md +3 -3
- package/.codex/skills/clean/SKILL.md +3 -3
- package/.codex/skills/issue-discover/SKILL.md +13 -13
- package/.codex/skills/issue-discover/phases/02-discover.md +4 -4
- package/.codex/skills/issue-discover/phases/03-discover-by-prompt.md +3 -3
- package/.codex/skills/parallel-dev-cycle/SKILL.md +4 -4
- package/.codex/skills/parallel-dev-cycle/phases/02-agent-execution.md +6 -6
- package/.codex/skills/parallel-dev-cycle/phases/03-result-aggregation.md +10 -10
- package/.codex/skills/review-cycle/SKILL.md +10 -10
- package/.codex/skills/review-cycle/phases/02-parallel-review.md +6 -6
- package/.codex/skills/review-cycle/phases/04-iterative-deep-dive.md +4 -4
- package/.codex/skills/review-cycle/phases/07-fix-parallel-planning.md +4 -4
- package/.codex/skills/review-cycle/phases/08-fix-execution.md +2 -2
- package/.codex/skills/roadmap-with-file/SKILL.md +14 -14
- package/.codex/skills/spec-generator/README.md +1 -1
- package/.codex/skills/spec-generator/SKILL.md +184 -88
- package/.codex/skills/spec-generator/phases/01-5-requirement-clarification.md +4 -7
- package/.codex/skills/spec-generator/phases/01-discovery.md +30 -11
- package/.codex/skills/spec-generator/phases/02-product-brief.md +2 -5
- package/.codex/skills/spec-generator/phases/03-requirements.md +4 -6
- package/.codex/skills/spec-generator/phases/04-architecture.md +4 -6
- package/.codex/skills/spec-generator/phases/05-epics-stories.md +4 -6
- package/.codex/skills/spec-generator/phases/06-5-auto-fix.md +4 -5
- package/.codex/skills/spec-generator/phases/06-readiness-check.md +8 -8
- package/.codex/skills/spec-generator/phases/07-issue-export.md +2 -2
- package/.codex/skills/spec-setup/SKILL.md +4 -4
- package/.codex/skills/workflow-plan/SKILL.md +6 -6
- package/.codex/skills/workflow-tdd-plan/SKILL.md +5 -5
- package/.codex/skills/workflow-test-fix-cycle/SKILL.md +19 -19
- package/.codex/skills/workflow-test-fix-cycle/phases/01-test-fix-gen.md +5 -5
- package/.codex/skills/workflow-test-fix-cycle/phases/02-test-cycle-execute.md +5 -5
- package/ccw/frontend/dist/assets/{AlertDialog-BjP1ydDR.js → AlertDialog-exlTDW81.js} +3 -3
- package/ccw/frontend/dist/assets/{AlertDialog-BjP1ydDR.js.map → AlertDialog-exlTDW81.js.map} +1 -1
- package/ccw/frontend/dist/assets/{AnalysisPage-CAX3xqMf.js → AnalysisPage-cgV9LfAI.js} +2 -2
- package/ccw/frontend/dist/assets/{AnalysisPage-CAX3xqMf.js.map → AnalysisPage-cgV9LfAI.js.map} +1 -1
- package/ccw/frontend/dist/assets/{ApiSettingsPage-CtWlmztq.js → ApiSettingsPage-Dk5jJdWt.js} +2 -2
- package/ccw/frontend/dist/assets/{ApiSettingsPage-CtWlmztq.js.map → ApiSettingsPage-Dk5jJdWt.js.map} +1 -1
- package/ccw/frontend/dist/assets/{CliModeToggle-hR4a-eLX.js → CliModeToggle-Be9xsPiv.js} +2 -2
- package/ccw/frontend/dist/assets/{CliModeToggle-hR4a-eLX.js.map → CliModeToggle-Be9xsPiv.js.map} +1 -1
- package/ccw/frontend/dist/assets/{CliSessionSharePage-DzNPkFN9.js → CliSessionSharePage-Bh9jBtPI.js} +2 -2
- package/ccw/frontend/dist/assets/{CliSessionSharePage-DzNPkFN9.js.map → CliSessionSharePage-Bh9jBtPI.js.map} +1 -1
- package/ccw/frontend/dist/assets/{CliViewerPage-BPEGN4TT.js → CliViewerPage-BrE-oyEq.js} +2 -2
- package/ccw/frontend/dist/assets/{CliViewerPage-BPEGN4TT.js.map → CliViewerPage-BrE-oyEq.js.map} +1 -1
- package/ccw/frontend/dist/assets/{CodexLensPage-Cf0r2RHY.js → CodexLensPage-Cd3nrC93.js} +2 -2
- package/ccw/frontend/dist/assets/{CodexLensPage-Cf0r2RHY.js.map → CodexLensPage-Cd3nrC93.js.map} +1 -1
- package/ccw/frontend/dist/assets/{Collapsible-DEm1rJ4h.js → Collapsible-DXFl3VKF.js} +2 -2
- package/ccw/frontend/dist/assets/{Collapsible-DEm1rJ4h.js.map → Collapsible-DXFl3VKF.js.map} +1 -1
- package/ccw/frontend/dist/assets/{CommandsManagerPage-BpeWw8HO.js → CommandsManagerPage-IV8zpjgX.js} +2 -2
- package/ccw/frontend/dist/assets/{CommandsManagerPage-BpeWw8HO.js.map → CommandsManagerPage-IV8zpjgX.js.map} +1 -1
- package/ccw/frontend/dist/assets/{DeepWikiPage-BEsmh2vF.js → DeepWikiPage-CpDxtmRX.js} +2 -2
- package/ccw/frontend/dist/assets/{DeepWikiPage-BEsmh2vF.js.map → DeepWikiPage-CpDxtmRX.js.map} +1 -1
- package/ccw/frontend/dist/assets/{EndpointsPage-B30SFdtU.js → EndpointsPage-BchjWe7s.js} +2 -2
- package/ccw/frontend/dist/assets/{EndpointsPage-B30SFdtU.js.map → EndpointsPage-BchjWe7s.js.map} +1 -1
- package/ccw/frontend/dist/assets/{ExplorerPage-BVvMpg1O.js → ExplorerPage-CbWvaJ0y.js} +2 -2
- package/ccw/frontend/dist/assets/{ExplorerPage-BVvMpg1O.js.map → ExplorerPage-CbWvaJ0y.js.map} +1 -1
- package/ccw/frontend/dist/assets/{FixSessionPage-CL73dHbh.js → FixSessionPage-YMjVRiCk.js} +2 -2
- package/ccw/frontend/dist/assets/{FixSessionPage-CL73dHbh.js.map → FixSessionPage-YMjVRiCk.js.map} +1 -1
- package/ccw/frontend/dist/assets/{FloatingFileBrowser-BL-28lMZ.js → FloatingFileBrowser-JW2ehYY_.js} +2 -2
- package/ccw/frontend/dist/assets/{FloatingFileBrowser-BL-28lMZ.js.map → FloatingFileBrowser-JW2ehYY_.js.map} +1 -1
- package/ccw/frontend/dist/assets/{FloatingPanel-BzZDciHZ.js → FloatingPanel-BtqzqDVq.js} +2 -2
- package/ccw/frontend/dist/assets/{FloatingPanel-BzZDciHZ.js.map → FloatingPanel-BtqzqDVq.js.map} +1 -1
- package/ccw/frontend/dist/assets/{GraphExplorerPage-CDp6-d8P.js → GraphExplorerPage-BsJL_W4d.js} +3 -3
- package/ccw/frontend/dist/assets/{GraphExplorerPage-CDp6-d8P.js.map → GraphExplorerPage-BsJL_W4d.js.map} +1 -1
- package/ccw/frontend/dist/assets/{HistoryPage-fZY_7O9n.js → HistoryPage-BuWpQ7k5.js} +2 -2
- package/ccw/frontend/dist/assets/{HistoryPage-fZY_7O9n.js.map → HistoryPage-BuWpQ7k5.js.map} +1 -1
- package/ccw/frontend/dist/assets/{HookManagerPage-4LJeC9bq.js → HookManagerPage-D0BtMIWy.js} +2 -2
- package/ccw/frontend/dist/assets/{HookManagerPage-4LJeC9bq.js.map → HookManagerPage-D0BtMIWy.js.map} +1 -1
- package/ccw/frontend/dist/assets/{InstallationsPage-Bpigrbhw.js → InstallationsPage-C7dwsAKG.js} +2 -2
- package/ccw/frontend/dist/assets/{InstallationsPage-Bpigrbhw.js.map → InstallationsPage-C7dwsAKG.js.map} +1 -1
- package/ccw/frontend/dist/assets/{IssueHubPage-BP0zJc1R.js → IssueHubPage-D0nCNaeB.js} +2 -2
- package/ccw/frontend/dist/assets/{IssueHubPage-BP0zJc1R.js.map → IssueHubPage-D0nCNaeB.js.map} +1 -1
- package/ccw/frontend/dist/assets/{LiteTasksPage-CSt2oVKQ.js → LiteTasksPage-B5c2Kb9r.js} +3 -3
- package/ccw/frontend/dist/assets/{LiteTasksPage-CSt2oVKQ.js.map → LiteTasksPage-B5c2Kb9r.js.map} +1 -1
- package/ccw/frontend/dist/assets/{McpManagerPage-B-xaMA0w.js → McpManagerPage-C-S5CehM.js} +2 -2
- package/ccw/frontend/dist/assets/{McpManagerPage-B-xaMA0w.js.map → McpManagerPage-C-S5CehM.js.map} +1 -1
- package/ccw/frontend/dist/assets/{MemoryPage-CJqo_7DY.js → MemoryPage-P_B0JVUQ.js} +2 -2
- package/ccw/frontend/dist/assets/{MemoryPage-CJqo_7DY.js.map → MemoryPage-P_B0JVUQ.js.map} +1 -1
- package/ccw/frontend/dist/assets/{NotFoundPage-ibZeQA-Y.js → NotFoundPage-S4Jn9LUE.js} +2 -2
- package/ccw/frontend/dist/assets/{NotFoundPage-ibZeQA-Y.js.map → NotFoundPage-S4Jn9LUE.js.map} +1 -1
- package/ccw/frontend/dist/assets/{OrchestratorPage-DgJ4ctPQ.js → OrchestratorPage-C2Zlr7AC.js} +2 -2
- package/ccw/frontend/dist/assets/{OrchestratorPage-DgJ4ctPQ.js.map → OrchestratorPage-C2Zlr7AC.js.map} +1 -1
- package/ccw/frontend/dist/assets/{ProjectOverviewPage-Cit0Yq0D.js → ProjectOverviewPage-CMVfz8s5.js} +2 -2
- package/ccw/frontend/dist/assets/{ProjectOverviewPage-Cit0Yq0D.js.map → ProjectOverviewPage-CMVfz8s5.js.map} +1 -1
- package/ccw/frontend/dist/assets/{PromptHistoryPage-Ce1HDIK0.js → PromptHistoryPage-YEMjFARX.js} +3 -3
- package/ccw/frontend/dist/assets/{PromptHistoryPage-Ce1HDIK0.js.map → PromptHistoryPage-YEMjFARX.js.map} +1 -1
- package/ccw/frontend/dist/assets/{ReviewSessionPage-J1KikNrk.js → ReviewSessionPage-DnTm55nG.js} +2 -2
- package/ccw/frontend/dist/assets/{ReviewSessionPage-J1KikNrk.js.map → ReviewSessionPage-DnTm55nG.js.map} +1 -1
- package/ccw/frontend/dist/assets/{RulesManagerPage-CdBjTmth.js → RulesManagerPage-CUwebtO2.js} +2 -2
- package/ccw/frontend/dist/assets/{RulesManagerPage-CdBjTmth.js.map → RulesManagerPage-CUwebtO2.js.map} +1 -1
- package/ccw/frontend/dist/assets/{SessionDetailPage-B9ZK7LvX.js → SessionDetailPage-0qyH1Z5P.js} +2 -2
- package/ccw/frontend/dist/assets/{SessionDetailPage-B9ZK7LvX.js.map → SessionDetailPage-0qyH1Z5P.js.map} +1 -1
- package/ccw/frontend/dist/assets/{SessionsPage-CW_nS5UR.js → SessionsPage-BpgP4087.js} +2 -2
- package/ccw/frontend/dist/assets/{SessionsPage-CW_nS5UR.js.map → SessionsPage-BpgP4087.js.map} +1 -1
- package/ccw/frontend/dist/assets/SettingsPage-C3SJajeT.js +150 -0
- package/ccw/frontend/dist/assets/SettingsPage-C3SJajeT.js.map +1 -0
- package/ccw/frontend/dist/assets/SkillsManagerPage-vD9PTsmy.js +7 -0
- package/ccw/frontend/dist/assets/SkillsManagerPage-vD9PTsmy.js.map +1 -0
- package/ccw/frontend/dist/assets/{SpecsSettingsPage-DJpi9XQL.js → SpecsSettingsPage-DT-yTVkD.js} +4 -4
- package/ccw/frontend/dist/assets/{SpecsSettingsPage-DJpi9XQL.js.map → SpecsSettingsPage-DT-yTVkD.js.map} +1 -1
- package/ccw/frontend/dist/assets/{Switch-Ac6Ov7uy.js → Switch-CYSPdqWk.js} +2 -2
- package/ccw/frontend/dist/assets/{Switch-Ac6Ov7uy.js.map → Switch-CYSPdqWk.js.map} +1 -1
- package/ccw/frontend/dist/assets/{TabsNavigation-DZAAspqR.js → TabsNavigation-CPh6Zor1.js} +2 -2
- package/ccw/frontend/dist/assets/{TabsNavigation-DZAAspqR.js.map → TabsNavigation-CPh6Zor1.js.map} +1 -1
- package/ccw/frontend/dist/assets/{TaskDrawer-BJkwfhIZ.js → TaskDrawer-Ds-8830B.js} +2 -2
- package/ccw/frontend/dist/assets/{TaskDrawer-BJkwfhIZ.js.map → TaskDrawer-Ds-8830B.js.map} +1 -1
- package/ccw/frontend/dist/assets/{TeamPage-BJgjxBgb.js → TeamPage-CJODUxBk.js} +2 -2
- package/ccw/frontend/dist/assets/{TeamPage-BJgjxBgb.js.map → TeamPage-CJODUxBk.js.map} +1 -1
- package/ccw/frontend/dist/assets/{TerminalDashboardPage-D1WekoOy.js → TerminalDashboardPage-Cn3fGUuO.js} +3 -3
- package/ccw/frontend/dist/assets/{TerminalDashboardPage-D1WekoOy.js.map → TerminalDashboardPage-Cn3fGUuO.js.map} +1 -1
- package/ccw/frontend/dist/assets/{archive-DxemgIhF.js → archive-CjwVpw6k.js} +2 -2
- package/ccw/frontend/dist/assets/{archive-DxemgIhF.js.map → archive-CjwVpw6k.js.map} +1 -1
- package/ccw/frontend/dist/assets/{archive-restore-CjS83f1V.js → archive-restore-2vZa9Ic3.js} +2 -2
- package/ccw/frontend/dist/assets/{archive-restore-CjS83f1V.js.map → archive-restore-2vZa9Ic3.js.map} +1 -1
- package/ccw/frontend/dist/assets/{arrow-right-B5PUcn8I.js → arrow-right-CUU5XDgT.js} +2 -2
- package/ccw/frontend/dist/assets/{arrow-right-B5PUcn8I.js.map → arrow-right-CUU5XDgT.js.map} +1 -1
- package/ccw/frontend/dist/assets/{bookmark-plus-DCc9aPbb.js → bookmark-plus-Cc3nKRZ5.js} +2 -2
- package/ccw/frontend/dist/assets/{bookmark-plus-DCc9aPbb.js.map → bookmark-plus-Cc3nKRZ5.js.map} +1 -1
- package/ccw/frontend/dist/assets/{bot-DOwFtzak.js → bot-BwpSRDUa.js} +2 -2
- package/ccw/frontend/dist/assets/{bot-DOwFtzak.js.map → bot-BwpSRDUa.js.map} +1 -1
- package/ccw/frontend/dist/assets/{braces-96qH3aFh.js → braces-DBzUW1XC.js} +2 -2
- package/ccw/frontend/dist/assets/{braces-96qH3aFh.js.map → braces-DBzUW1XC.js.map} +1 -1
- package/ccw/frontend/dist/assets/{circle-stop-CCxSuil1.js → circle-stop-CGNNsjvE.js} +2 -2
- package/ccw/frontend/dist/assets/{circle-stop-CCxSuil1.js.map → circle-stop-CGNNsjvE.js.map} +1 -1
- package/ccw/frontend/dist/assets/{cpu-CZNSJFdq.js → cpu-D27G86Ul.js} +2 -2
- package/ccw/frontend/dist/assets/{cpu-CZNSJFdq.js.map → cpu-D27G86Ul.js.map} +1 -1
- package/ccw/frontend/dist/assets/{ellipsis-vertical-h8xtvw2_.js → ellipsis-vertical-C1Ij47Yz.js} +2 -2
- package/ccw/frontend/dist/assets/{ellipsis-vertical-h8xtvw2_.js.map → ellipsis-vertical-C1Ij47Yz.js.map} +1 -1
- package/ccw/frontend/dist/assets/{eye-D3NY0bm6.js → eye-C6MOB7Au.js} +2 -2
- package/ccw/frontend/dist/assets/{eye-D3NY0bm6.js.map → eye-C6MOB7Au.js.map} +1 -1
- package/ccw/frontend/dist/assets/{eye-off-Cy2vkc8p.js → eye-off-BxfBlZ26.js} +2 -2
- package/ccw/frontend/dist/assets/{eye-off-Cy2vkc8p.js.map → eye-off-BxfBlZ26.js.map} +1 -1
- package/ccw/frontend/dist/assets/{file-json-Bzq3U1Mx.js → file-json-NI237wA-.js} +2 -2
- package/ccw/frontend/dist/assets/{file-json-Bzq3U1Mx.js.map → file-json-NI237wA-.js.map} +1 -1
- package/ccw/frontend/dist/assets/{file-text-DwuwPDPi.js → file-text-Byn2_2v6.js} +2 -2
- package/ccw/frontend/dist/assets/{file-text-DwuwPDPi.js.map → file-text-Byn2_2v6.js.map} +1 -1
- package/ccw/frontend/dist/assets/{filter-q9g-bknU.js → filter-D-7PhZjx.js} +2 -2
- package/ccw/frontend/dist/assets/{filter-q9g-bknU.js.map → filter-D-7PhZjx.js.map} +1 -1
- package/ccw/frontend/dist/assets/{folder-CL6vb42J.js → folder-BoAsK_FL.js} +2 -2
- package/ccw/frontend/dist/assets/{folder-CL6vb42J.js.map → folder-BoAsK_FL.js.map} +1 -1
- package/ccw/frontend/dist/assets/{gauge-BkrcQBly.js → gauge-DCSxJIS4.js} +2 -2
- package/ccw/frontend/dist/assets/{gauge-BkrcQBly.js.map → gauge-DCSxJIS4.js.map} +1 -1
- package/ccw/frontend/dist/assets/{globe-BQbwyNeV.js → globe-CHS3prza.js} +2 -2
- package/ccw/frontend/dist/assets/{globe-BQbwyNeV.js.map → globe-CHS3prza.js.map} +1 -1
- package/ccw/frontend/dist/assets/{grid-3x3-x5_7DrN7.js → grid-3x3-D7K35U7S.js} +2 -2
- package/ccw/frontend/dist/assets/{grid-3x3-x5_7DrN7.js.map → grid-3x3-D7K35U7S.js.map} +1 -1
- package/ccw/frontend/dist/assets/{hard-drive-DTyWXwzf.js → hard-drive-eq9xE07G.js} +2 -2
- package/ccw/frontend/dist/assets/{hard-drive-DTyWXwzf.js.map → hard-drive-eq9xE07G.js.map} +1 -1
- package/ccw/frontend/dist/assets/{hash-80O0kJO7.js → hash-C1DMpBua.js} +2 -2
- package/ccw/frontend/dist/assets/{hash-80O0kJO7.js.map → hash-C1DMpBua.js.map} +1 -1
- package/ccw/frontend/dist/assets/{history-DDlN2Bwa.js → history-Di5SBCY-.js} +2 -2
- package/ccw/frontend/dist/assets/{history-DDlN2Bwa.js.map → history-Di5SBCY-.js.map} +1 -1
- package/ccw/frontend/dist/assets/{index-mbeo62f8.js → index--_R7COnA.js} +2 -2
- package/ccw/frontend/dist/assets/{index-mbeo62f8.js.map → index--_R7COnA.js.map} +1 -1
- package/ccw/frontend/dist/assets/{index-rLgoBCfV.js → index-BUol9HDD.js} +3 -3
- package/ccw/frontend/dist/assets/{index-rLgoBCfV.js.map → index-BUol9HDD.js.map} +1 -1
- package/ccw/frontend/dist/assets/{index-Bs80iCX0.js → index-CT9oykfw.js} +2 -2
- package/ccw/frontend/dist/assets/{index-Bs80iCX0.js.map → index-CT9oykfw.js.map} +1 -1
- package/ccw/frontend/dist/assets/{index-B9A3Hnrk.js → index-Ddwvf87H.js} +2 -2
- package/ccw/frontend/dist/assets/{index-B9A3Hnrk.js.map → index-Ddwvf87H.js.map} +1 -1
- package/ccw/frontend/dist/assets/{layout-grid-C1niOWJx.js → layout-grid-LiX0qZbN.js} +2 -2
- package/ccw/frontend/dist/assets/{layout-grid-C1niOWJx.js.map → layout-grid-LiX0qZbN.js.map} +1 -1
- package/ccw/frontend/dist/assets/{lightbulb-BTmI7SUg.js → lightbulb-CL3DVEwb.js} +2 -2
- package/ccw/frontend/dist/assets/{lightbulb-BTmI7SUg.js.map → lightbulb-CL3DVEwb.js.map} +1 -1
- package/ccw/frontend/dist/assets/{link-2-CB9HKeuZ.js → link-2-CC5cFeq6.js} +2 -2
- package/ccw/frontend/dist/assets/{link-2-CB9HKeuZ.js.map → link-2-CC5cFeq6.js.map} +1 -1
- package/ccw/frontend/dist/assets/{link-koEYiemK.js → link-ngFQ9bs0.js} +2 -2
- package/ccw/frontend/dist/assets/{link-koEYiemK.js.map → link-ngFQ9bs0.js.map} +1 -1
- package/ccw/frontend/dist/assets/{list-v2_GaLdC.js → list-BEU6I0KK.js} +2 -2
- package/ccw/frontend/dist/assets/{list-v2_GaLdC.js.map → list-BEU6I0KK.js.map} +1 -1
- package/ccw/frontend/dist/assets/{map-pin-BQNfAqG_.js → map-pin-BWZdLA6y.js} +2 -2
- package/ccw/frontend/dist/assets/{map-pin-BQNfAqG_.js.map → map-pin-BWZdLA6y.js.map} +1 -1
- package/ccw/frontend/dist/assets/{messages-square-Dzq5LGg9.js → messages-square-K6_Chm7n.js} +2 -2
- package/ccw/frontend/dist/assets/{messages-square-Dzq5LGg9.js.map → messages-square-K6_Chm7n.js.map} +1 -1
- package/ccw/frontend/dist/assets/{minimize-2-CtkoJXcz.js → minimize-2-CWkphauf.js} +2 -2
- package/ccw/frontend/dist/assets/{minimize-2-CtkoJXcz.js.map → minimize-2-CWkphauf.js.map} +1 -1
- package/ccw/frontend/dist/assets/{package-CH3smL37.js → package-DrNgkamn.js} +2 -2
- package/ccw/frontend/dist/assets/{package-CH3smL37.js.map → package-DrNgkamn.js.map} +1 -1
- package/ccw/frontend/dist/assets/{plug-CZ0aL_yF.js → plug-CMo3sw5_.js} +2 -2
- package/ccw/frontend/dist/assets/{plug-CZ0aL_yF.js.map → plug-CMo3sw5_.js.map} +1 -1
- package/ccw/frontend/dist/assets/{power-F2A_J4l6.js → power-DppNTW5e.js} +2 -2
- package/ccw/frontend/dist/assets/{power-F2A_J4l6.js.map → power-DppNTW5e.js.map} +1 -1
- package/ccw/frontend/dist/assets/{save-Byxot0YU.js → save-CD8aPMbZ.js} +2 -2
- package/ccw/frontend/dist/assets/{save-Byxot0YU.js.map → save-CD8aPMbZ.js.map} +1 -1
- package/ccw/frontend/dist/assets/{send-JjqhUkpw.js → send-B4z90fQD.js} +2 -2
- package/ccw/frontend/dist/assets/{send-JjqhUkpw.js.map → send-B4z90fQD.js.map} +1 -1
- package/ccw/frontend/dist/assets/{settings-2--SuN9rAt.js → settings-2-CAKRU_QC.js} +2 -2
- package/ccw/frontend/dist/assets/{settings-2--SuN9rAt.js.map → settings-2-CAKRU_QC.js.map} +1 -1
- package/ccw/frontend/dist/assets/{square-check-big-BbngGB2h.js → square-check-big-KhI3HrzX.js} +2 -2
- package/ccw/frontend/dist/assets/{square-check-big-BbngGB2h.js.map → square-check-big-KhI3HrzX.js.map} +1 -1
- package/ccw/frontend/dist/assets/{square-pen-CgrHgZSl.js → square-pen-BtdGIpuq.js} +2 -2
- package/ccw/frontend/dist/assets/{square-pen-CgrHgZSl.js.map → square-pen-BtdGIpuq.js.map} +1 -1
- package/ccw/frontend/dist/assets/{star-BU3TQr7Z.js → star-ZoBUkXoD.js} +2 -2
- package/ccw/frontend/dist/assets/{star-BU3TQr7Z.js.map → star-ZoBUkXoD.js.map} +1 -1
- package/ccw/frontend/dist/assets/{style-CKs7nnn3.js → style-CltxQP-P.js} +2 -2
- package/ccw/frontend/dist/assets/{style-CKs7nnn3.js.map → style-CltxQP-P.js.map} +1 -1
- package/ccw/frontend/dist/assets/{target-DW5tsDW6.js → target-C32OUSGf.js} +2 -2
- package/ccw/frontend/dist/assets/{target-DW5tsDW6.js.map → target-C32OUSGf.js.map} +1 -1
- package/ccw/frontend/dist/assets/{test-tube-BHm7w3ON.js → test-tube-0IxoyAVZ.js} +2 -2
- package/ccw/frontend/dist/assets/{test-tube-BHm7w3ON.js.map → test-tube-0IxoyAVZ.js.map} +1 -1
- package/ccw/frontend/dist/assets/{upload-DYR7PWwt.js → upload-4eKCkyBn.js} +2 -2
- package/ccw/frontend/dist/assets/{upload-DYR7PWwt.js.map → upload-4eKCkyBn.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useApiSettings-D0TVgQD_.js → useApiSettings-zLTUWqhi.js} +2 -2
- package/ccw/frontend/dist/assets/{useApiSettings-D0TVgQD_.js.map → useApiSettings-zLTUWqhi.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useCli-DfY8mAP8.js → useCli-BtN2vpOX.js} +2 -2
- package/ccw/frontend/dist/assets/{useCli-DfY8mAP8.js.map → useCli-BtN2vpOX.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useCommands-CGusDp0F.js → useCommands-_spj49qL.js} +2 -2
- package/ccw/frontend/dist/assets/{useCommands-CGusDp0F.js.map → useCommands-_spj49qL.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useDebounce-CIwh0fF1.js → useDebounce-Bm9KFZvd.js} +2 -2
- package/ccw/frontend/dist/assets/{useDebounce-CIwh0fF1.js.map → useDebounce-Bm9KFZvd.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useFileExplorer-FMyFv39K.js → useFileExplorer-DOmpm6v9.js} +2 -2
- package/ccw/frontend/dist/assets/{useFileExplorer-FMyFv39K.js.map → useFileExplorer-DOmpm6v9.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useLocale-B2qhsoTb.js → useLocale-D2rj4rea.js} +2 -2
- package/ccw/frontend/dist/assets/{useLocale-B2qhsoTb.js.map → useLocale-D2rj4rea.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useSkills-cxKXMBm3.js → useSkills-OskEpomF.js} +3 -3
- package/ccw/frontend/dist/assets/{useSkills-cxKXMBm3.js.map → useSkills-OskEpomF.js.map} +1 -1
- package/ccw/frontend/dist/assets/{useSystemSettings-B-xUT_z-.js → useSystemSettings-BjMgsNSF.js} +2 -2
- package/ccw/frontend/dist/assets/{useSystemSettings-B-xUT_z-.js.map → useSystemSettings-BjMgsNSF.js.map} +1 -1
- package/ccw/frontend/dist/assets/{wand-sparkles-DZV_3lPr.js → wand-sparkles-CLhyYWa7.js} +2 -2
- package/ccw/frontend/dist/assets/{wand-sparkles-DZV_3lPr.js.map → wand-sparkles-CLhyYWa7.js.map} +1 -1
- package/ccw/frontend/dist/index.html +1 -1
- package/package.json +1 -1
- package/ccw/frontend/dist/assets/SettingsPage-B2PYzSoO.js +0 -150
- package/ccw/frontend/dist/assets/SettingsPage-B2PYzSoO.js.map +0 -1
- package/ccw/frontend/dist/assets/SkillsManagerPage-CTnWrrwp.js +0 -7
- package/ccw/frontend/dist/assets/SkillsManagerPage-CTnWrrwp.js.map +0 -1
package/ccw/frontend/dist/assets/{useFileExplorer-FMyFv39K.js.map → useFileExplorer-DOmpm6v9.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useFileExplorer-FMyFv39K.js","sources":["../../src/components/shared/TreeView.tsx","../../src/components/shared/FilePreview.tsx","../../src/hooks/useFileExplorer.ts"],"sourcesContent":["// ========================================\n// TreeView Component\n// ========================================\n// Recursive tree view component for file explorer using native HTML details/summary\n\nimport * as React from 'react';\nimport { ChevronRight, File, Folder, FolderOpen, FileCode } from 'lucide-react';\nimport { cn } from '@/lib/utils';\nimport type { FileSystemNode } from '@/types/file-explorer';\n\nexport interface TreeViewProps {\n /** Root nodes of the file tree */\n nodes: FileSystemNode[];\n /** Set of expanded directory paths */\n expandedPaths: Set<string>;\n /** Currently selected file path */\n selectedPath: string | null;\n /** Callback when node is clicked */\n onNodeClick?: (node: FileSystemNode) => void;\n /** Callback when node is double-clicked */\n onNodeDoubleClick?: (node: FileSystemNode) => void;\n /** Callback to toggle expanded state */\n onToggle?: (path: string) => void;\n /** Maximum depth to display (0 = unlimited) */\n maxDepth?: number;\n /** Current depth level */\n depth?: number;\n /** Whether to show file icons */\n showIcons?: boolean;\n /** Whether to show file sizes */\n showSizes?: boolean;\n /** Custom class name */\n className?: string;\n}\n\ninterface TreeNodeProps {\n node: FileSystemNode;\n level: number;\n expandedPaths: Set<string>;\n selectedPath: string | null;\n maxDepth?: number;\n showIcons?: boolean;\n showSizes?: boolean;\n onNodeClick?: (node: FileSystemNode) => void;\n onNodeDoubleClick?: (node: FileSystemNode) => void;\n onToggle?: (path: string) => void;\n}\n\n/**\n * Get file icon based on file extension\n */\nfunction getFileIcon(fileName: string): React.ElementType {\n const ext = fileName.split('.').pop()?.toLowerCase();\n \n const codeExtensions = ['ts', 'tsx', 'js', 'jsx', 'vue', 'svelte', 'py', 'rb', 'go', 'rs', 'java', 'cs', 'php', 'scala', 'kt'];\n const configExtensions = ['json', 'yaml', 'yml', 'toml', 'ini', 'conf', 'xml', 'config'];\n \n if (codeExtensions.includes(ext || '')) {\n return FileCode;\n }\n if (configExtensions.includes(ext || '')) {\n return FileCode;\n }\n \n return File;\n}\n\n/**\n * Get file size in human-readable format\n */\nfunction formatFileSize(bytes?: number): string {\n if (!bytes) return '';\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unitIndex = 0;\n \n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n \n return `${size.toFixed(1)}${units[unitIndex]}`;\n}\n\n/**\n * TreeNode component - renders a single tree node with children\n */\nfunction TreeNode({\n node,\n level,\n expandedPaths,\n selectedPath,\n maxDepth = 0,\n showIcons = true,\n showSizes = false,\n onNodeClick,\n onNodeDoubleClick,\n onToggle,\n}: TreeNodeProps) {\n const isDirectory = node.type === 'directory';\n const isExpanded = expandedPaths.has(node.path);\n const isSelected = selectedPath === node.path;\n const hasChildren = isDirectory && node.children && node.children.length > 0;\n const shouldShowChildren = isExpanded && hasChildren;\n const isAtMaxDepth = maxDepth > 0 && level >= maxDepth;\n\n // Get icon component\n let Icon: React.ElementType = File;\n if (isDirectory) {\n Icon = isExpanded ? FolderOpen : Folder;\n } else if (showIcons) {\n Icon = getFileIcon(node.name);\n }\n\n // Handle click\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onNodeClick?.(node);\n \n // Toggle directories on click\n if (isDirectory && hasChildren) {\n onToggle?.(node.path);\n }\n };\n\n // Handle double click\n const handleDoubleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onNodeDoubleClick?.(node);\n };\n\n // Handle key press for accessibility\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick(e as any);\n }\n };\n\n return (\n <div\n className={cn(\n 'tree-node',\n isDirectory && 'tree-directory',\n isSelected && 'selected'\n )}\n role=\"treeitem\"\n aria-expanded={isDirectory ? isExpanded : undefined}\n aria-selected={isSelected}\n >\n {/* Node content */}\n <div\n className={cn(\n 'flex items-center gap-1 px-2 py-1 rounded-sm cursor-pointer transition-colors',\n 'hover:bg-hover hover:text-foreground',\n isSelected && 'bg-primary/10 text-primary',\n 'text-foreground text-sm'\n )}\n style={{ paddingLeft: `${level * 16 + 8}px` }}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n onKeyDown={handleKeyDown}\n tabIndex={0}\n title={node.path}\n >\n {/* Expand/collapse chevron for directories */}\n {isDirectory && (\n <ChevronRight\n className={cn(\n 'h-4 w-4 flex-shrink-0 text-muted-foreground transition-transform',\n isExpanded && 'rotate-90'\n )}\n />\n )}\n \n {/* Folder/File icon */}\n {showIcons && (\n <Icon\n className={cn(\n 'h-4 w-4 flex-shrink-0',\n isDirectory\n ? isExpanded\n ? 'text-blue-500'\n : 'text-blue-400'\n : 'text-muted-foreground'\n )}\n />\n )}\n\n {/* Node name */}\n <span className=\"flex-1 truncate\">{node.name}</span>\n\n {/* CLAUDE.md indicator */}\n {node.hasClaudeMd && (\n <span\n className=\"ml-1 px-1.5 py-0.5 text-[10px] font-semibold rounded bg-purple-500/20 text-purple-500\"\n title=\"Contains CLAUDE.md context\"\n >\n MD\n </span>\n )}\n\n {/* File size */}\n {showSizes && !isDirectory && node.size && (\n <span className=\"text-xs text-muted-foreground ml-auto\">\n {formatFileSize(node.size)}\n </span>\n )}\n </div>\n\n {/* Recursive children */}\n {shouldShowChildren && !isAtMaxDepth && node.children && (\n <div className=\"tree-children\" role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.path}\n node={child}\n level={level + 1}\n expandedPaths={expandedPaths}\n selectedPath={selectedPath}\n maxDepth={maxDepth}\n showIcons={showIcons}\n showSizes={showSizes}\n onNodeClick={onNodeClick}\n onNodeDoubleClick={onNodeDoubleClick}\n onToggle={onToggle}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/**\n * TreeView component - displays file tree with expand/collapse\n *\n * @example\n * ```tsx\n * <TreeView\n * nodes={fileTree}\n * expandedPaths={expandedPaths}\n * selectedPath={selectedFile}\n * onNodeClick={(node) => console.log('Clicked:', node.path)}\n * onToggle={(path) => toggleExpanded(path)}\n * showIcons\n * showSizes\n * />\n * ```\n */\nexport function TreeView({\n nodes,\n expandedPaths,\n selectedPath,\n onNodeClick,\n onNodeDoubleClick,\n onToggle,\n maxDepth = 0,\n depth = 0,\n showIcons = true,\n showSizes = false,\n className,\n}: TreeViewProps) {\n if (nodes.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center py-8 px-4 text-center\">\n <Folder className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <p className=\"text-sm text-muted-foreground\">No files found</p>\n </div>\n );\n }\n\n return (\n <div\n className={cn('tree-view', className)}\n role=\"tree\"\n aria-label=\"File tree\"\n >\n {nodes.map((node) => (\n <TreeNode\n key={node.path}\n node={node}\n level={depth}\n expandedPaths={expandedPaths}\n selectedPath={selectedPath}\n maxDepth={maxDepth}\n showIcons={showIcons}\n showSizes={showSizes}\n onNodeClick={onNodeClick}\n onNodeDoubleClick={onNodeDoubleClick}\n onToggle={onToggle}\n />\n ))}\n </div>\n );\n}\n\nexport default TreeView;\n","// ========================================\n// FilePreview Component\n// ========================================\n// File content preview with syntax highlighting\n\nimport * as React from 'react';\nimport { File, Copy, Check, AlertCircle, Loader2 } from 'lucide-react';\nimport { useIntl } from 'react-intl';\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button';\nimport type { FileContent } from '@/types/file-explorer';\n\nexport interface FilePreviewProps {\n /** File content to display */\n fileContent: FileContent | null | undefined;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: string | null;\n /** Custom class name */\n className?: string;\n /** Maximum file size to preview in bytes */\n maxSize?: number;\n /** Whether to show line numbers */\n showLineNumbers?: boolean;\n}\n\n/**\n * Get language display name\n */\nfunction getLanguageDisplayName(language?: string): string {\n if (!language) return 'Plain Text';\n \n const languageNames: Record<string, string> = {\n 'typescript': 'TypeScript',\n 'tsx': 'TypeScript JSX',\n 'javascript': 'JavaScript',\n 'jsx': 'React JSX',\n 'python': 'Python',\n 'ruby': 'Ruby',\n 'go': 'Go',\n 'rust': 'Rust',\n 'java': 'Java',\n 'csharp': 'C#',\n 'php': 'PHP',\n 'scala': 'Scala',\n 'kotlin': 'Kotlin',\n 'markdown': 'Markdown',\n 'json': 'JSON',\n 'yaml': 'YAML',\n 'xml': 'XML',\n 'html': 'HTML',\n 'css': 'CSS',\n 'scss': 'SCSS',\n 'less': 'Less',\n 'sql': 'SQL',\n 'bash': 'Bash',\n 'text': 'Plain Text',\n };\n \n return languageNames[language] || language.charAt(0).toUpperCase() + language.slice(1);\n}\n\n/**\n * Get file extension from path\n */\nfunction getFileExtension(path: string): string {\n const parts = path.split('.');\n return parts.length > 1 ? parts[parts.length - 1] : '';\n}\n\n/**\n * Check if file is likely binary\n */\nfunction isBinaryFile(path: string): boolean {\n const binaryExtensions = [\n 'png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'webp', 'svg',\n 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',\n 'zip', 'tar', 'gz', 'rar', '7z',\n 'mp3', 'mp4', 'avi', 'mov', 'wav',\n 'ttf', 'otf', 'woff', 'woff2', 'eot',\n 'exe', 'dll', 'so', 'dylib',\n 'class', 'jar', 'war',\n 'pdb', 'obj', 'o',\n ];\n \n const ext = getFileExtension(path).toLowerCase();\n return binaryExtensions.includes(ext);\n}\n\n/**\n * Format file size for display\n */\nfunction formatFileSize(bytes?: number): string {\n if (!bytes) return '';\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unitIndex = 0;\n \n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n \n return `${size.toFixed(1)} ${units[unitIndex]}`;\n}\n\n/**\n * Truncate content if too large\n */\nfunction truncateContent(content: string, maxLines: number = 1000): string {\n const lines = content.split('\\n');\n if (lines.length <= maxLines) return content;\n \n return lines.slice(0, maxLines).join('\\n') + `\\n\\n... (${lines.length - maxLines} more lines)`;\n}\n\n/**\n * FilePreview component\n */\nexport function FilePreview({\n fileContent,\n isLoading = false,\n error = null,\n className,\n maxSize = 1024 * 1024, // 1MB default\n showLineNumbers = true,\n}: FilePreviewProps) {\n const { formatMessage } = useIntl();\n const [copied, setCopied] = React.useState(false);\n const contentRef = React.useRef<HTMLPreElement>(null);\n\n // Copy content to clipboard\n const handleCopy = async () => {\n if (!fileContent?.content) return;\n \n try {\n await navigator.clipboard.writeText(fileContent.content);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.error('Failed to copy content:', err);\n }\n };\n\n // Loading state\n if (isLoading) {\n return (\n <div className={cn('flex items-center justify-center py-12', className)}>\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n <span className=\"ml-3 text-sm text-muted-foreground\">\n {formatMessage({ id: 'explorer.preview.loading' })}\n </span>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <AlertCircle className=\"h-12 w-12 text-destructive mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.errorTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground max-w-md\">{error}</p>\n </div>\n );\n }\n\n // Empty state\n if (!fileContent) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <File className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.emptyTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {formatMessage({ id: 'explorer.preview.emptyMessage' })}\n </p>\n </div>\n );\n }\n\n // Check if file is too large\n const isTooLarge = maxSize > 0 && (fileContent.size || 0) > maxSize;\n const isBinary = isBinaryFile(fileContent.path);\n\n // Binary file warning\n if (isBinary) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <File className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.binaryTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground mb-4\">\n {formatMessage({ id: 'explorer.preview.binaryMessage' })}\n </p>\n <div className=\"text-xs text-muted-foreground\">\n <span>{fileContent.path}</span>\n {fileContent.size && (\n <span className=\"ml-2\">({formatFileSize(fileContent.size)})</span>\n )}\n </div>\n </div>\n );\n }\n\n // File too large warning\n if (isTooLarge) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <AlertCircle className=\"h-12 w-12 text-warning mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.tooLargeTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground mb-4\">\n {formatMessage(\n { id: 'explorer.preview.tooLargeMessage' },\n { size: formatFileSize(maxSize) }\n )}\n </p>\n <div className=\"text-xs text-muted-foreground\">\n <span>{fileContent.path}</span>\n {fileContent.size && (\n <span className=\"ml-2\">({formatFileSize(fileContent.size)})</span>\n )}\n </div>\n </div>\n );\n }\n\n // Get file name and extension\n const fileName = fileContent.path.split('/').pop() || '';\n const extension = getFileExtension(fileContent.path);\n const language = fileContent.language || getLanguageDisplayName(fileContent.language);\n const truncatedContent = truncateContent(fileContent.content);\n\n // Split into lines for line numbers\n const lines = truncatedContent.split('\\n');\n\n return (\n <div className={cn('file-preview flex flex-col h-full', className)}>\n {/* Preview header */}\n <div className=\"flex items-center justify-between px-4 py-2 border-b border-border bg-muted/30\">\n <div className=\"flex items-center gap-2 min-w-0 flex-1\">\n <File className=\"h-4 w-4 text-muted-foreground flex-shrink-0\" />\n <span className=\"text-sm font-medium truncate\">{fileName}</span>\n {extension && (\n <span className=\"text-xs text-muted-foreground uppercase\">.{extension}</span>\n )}\n {fileContent.size && (\n <span className=\"text-xs text-muted-foreground\">\n ({formatFileSize(fileContent.size)})\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {fileContent.language && (\n <span className=\"text-xs text-muted-foreground px-2 py-0.5 rounded bg-muted\">\n {language}\n </span>\n )}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 w-7 p-0\"\n onClick={handleCopy}\n title={formatMessage({ id: 'explorer.preview.copy' })}\n >\n {copied ? (\n <Check className=\"h-4 w-4 text-success\" />\n ) : (\n <Copy className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </div>\n\n {/* Content area */}\n <div className=\"flex-1 overflow-auto custom-scrollbar\">\n <pre\n ref={contentRef}\n className={cn(\n 'text-sm p-4 m-0 bg-background',\n 'font-mono leading-relaxed',\n 'whitespace-pre-wrap break-words',\n '[&_::selection]:bg-primary/20 [&_::selection]:text-primary'\n )}\n >\n {showLineNumbers ? (\n <div className=\"flex\">\n {/* Line numbers */}\n <div className=\"text-right text-muted-foreground select-none pr-4 border-r border-border mr-4 min-w-[3rem]\">\n {lines.map((_, i) => (\n <div key={i} className=\"leading-relaxed\">\n {i + 1}\n </div>\n ))}\n </div>\n {/* Code content */}\n <code className=\"flex-1\">{truncatedContent}</code>\n </div>\n ) : (\n <code>{truncatedContent}</code>\n )}\n </pre>\n </div>\n\n {/* Footer with metadata */}\n {fileContent.modifiedTime && (\n <div className=\"px-4 py-2 border-t border-border text-xs text-muted-foreground\">\n {formatMessage(\n { id: 'explorer.preview.lastModified' },\n { time: new Date(fileContent.modifiedTime).toLocaleString() }\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport default FilePreview;\n","// ========================================\n// useFileExplorer Hook\n// ========================================\n// TanStack Query hooks for File Explorer with WebSocket subscription\n\nimport { useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useState, useCallback, useEffect, useRef } from 'react';\nimport {\n fetchFileTree,\n fetchFileContent,\n fetchRootDirectories,\n searchFiles,\n type RootDirectory,\n type SearchFilesResponse,\n} from '../lib/api';\nimport type { FileSystemNode, FileContent, ExplorerState } from '../types/file-explorer';\n\n// Query key factory\nexport const fileExplorerKeys = {\n all: ['fileExplorer'] as const,\n trees: () => [...fileExplorerKeys.all, 'tree'] as const,\n tree: (rootPath: string) => [...fileExplorerKeys.trees(), rootPath] as const,\n contents: () => [...fileExplorerKeys.all, 'content'] as const,\n content: (path: string) => [...fileExplorerKeys.contents(), path] as const,\n roots: () => [...fileExplorerKeys.all, 'roots'] as const,\n search: (query: string) => [...fileExplorerKeys.all, 'search', query] as const,\n};\n\n// Default stale time: 5 minutes for file tree (stable structure)\nconst TREE_STALE_TIME = 5 * 60 * 1000;\n// Default stale time: 10 minutes for file content\nconst CONTENT_STALE_TIME = 10 * 60 * 1000;\n\nexport interface UseFileExplorerOptions {\n /** Root directory path (default: '/') */\n rootPath?: string;\n /** Maximum tree depth (0 = unlimited) */\n maxDepth?: number;\n /** Include hidden files */\n includeHidden?: boolean;\n /** File patterns to exclude (glob patterns) */\n excludePatterns?: string[];\n /** Override default stale time (ms) */\n staleTime?: number;\n /** Enable/disable the query */\n enabled?: boolean;\n}\n\nexport interface UseFileExplorerReturn {\n /** Current explorer state */\n state: ExplorerState;\n /** Root nodes of the file tree */\n rootNodes: FileSystemNode[];\n /** Loading state for initial fetch */\n isLoading: boolean;\n /** Fetching state (initial or refetch) */\n isFetching: boolean;\n /** Error object if query failed */\n error: Error | null;\n /** Manually refetch file tree */\n refetch: () => Promise<void>;\n /** Set the selected file path */\n setSelectedFile: (path: string | null) => void;\n /** Toggle directory expanded state */\n toggleExpanded: (path: string) => void;\n /** Expand a directory */\n expandDirectory: (path: string) => void;\n /** Collapse a directory */\n collapseDirectory: (path: string) => void;\n /** Expand all directories */\n expandAll: () => void;\n /** Collapse all directories */\n collapseAll: () => void;\n /** Set view mode */\n setViewMode: (mode: ExplorerState['viewMode']) => void;\n /** Set sort order */\n setSortOrder: (order: ExplorerState['sortOrder']) => void;\n /** Toggle hidden files visibility */\n toggleShowHidden: () => void;\n /** Set filter string */\n setFilter: (filter: string) => void;\n /** Load file content */\n loadFileContent: (path: string) => Promise<FileContent | undefined>;\n /** Available root directories */\n rootDirectories: RootDirectory[] | undefined;\n /** Root directories loading state */\n isLoadingRoots: boolean;\n /** Search files */\n searchFiles: (query: string) => Promise<SearchFilesResponse | undefined>;\n /** Search results */\n searchResults: SearchFilesResponse | undefined;\n /** Is searching */\n isSearching: boolean;\n /** Clear file content cache */\n clearFileCache: (path?: string) => void;\n}\n\n/**\n * Hook for File Explorer with WebSocket subscription for real-time updates\n *\n * @example\n * ```tsx\n * const { rootNodes, state, setSelectedFile, toggleExpanded } = useFileExplorer({\n * rootPath: '/src'\n * });\n * ```\n */\nexport function useFileExplorer(options: UseFileExplorerOptions = {}): UseFileExplorerReturn {\n const {\n rootPath = '/',\n maxDepth = 5,\n // includeHidden is now controlled by internal showHiddenFiles state\n excludePatterns,\n staleTime,\n enabled = true,\n } = options;\n\n const queryClient = useQueryClient();\n\n // Explorer state\n const [expandedPaths, setExpandedPaths] = useState<Set<string>>(new Set([rootPath]));\n const [selectedFile, setSelectedFileState] = useState<string | null>(null);\n const [viewMode, setViewModeState] = useState<ExplorerState['viewMode']>('tree');\n const [sortOrder, setSortOrderState] = useState<ExplorerState['sortOrder']>('name');\n const [showHiddenFiles, setShowHiddenFiles] = useState(false);\n const [filter, setFilterState] = useState('');\n const [searchResults, setSearchResults] = useState<SearchFilesResponse | undefined>();\n\n // Fetch file tree - use showHiddenFiles state instead of options.includeHidden\n const treeQuery = useQuery({\n queryKey: [...fileExplorerKeys.tree(rootPath), { showHidden: showHiddenFiles }],\n queryFn: () => fetchFileTree(rootPath, { maxDepth, includeHidden: showHiddenFiles, excludePatterns }),\n staleTime: staleTime ?? TREE_STALE_TIME,\n enabled,\n retry: 2,\n retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000),\n });\n\n // Fetch root directories\n const rootsQuery = useQuery({\n queryKey: fileExplorerKeys.roots(),\n queryFn: fetchRootDirectories,\n staleTime: TREE_STALE_TIME,\n enabled,\n retry: 1,\n });\n\n const rootNodes = treeQuery.data?.rootNodes ?? [];\n const rootDirectories = rootsQuery.data;\n\n // Toggle expanded state\n const toggleExpanded = useCallback((path: string) => {\n setExpandedPaths((prev) => {\n const next = new Set(prev);\n if (next.has(path)) {\n next.delete(path);\n } else {\n next.add(path);\n }\n return next;\n });\n }, []);\n\n // Expand directory\n const expandDirectory = useCallback((path: string) => {\n setExpandedPaths((prev) => new Set([...prev, path]));\n }, []);\n\n // Collapse directory\n const collapseDirectory = useCallback((path: string) => {\n setExpandedPaths((prev) => {\n const next = new Set(prev);\n next.delete(path);\n return next;\n });\n }, []);\n\n // Expand all directories\n const expandAll = useCallback(() => {\n const allPaths = new Set<string>();\n const collectPaths = (nodes: FileSystemNode[]) => {\n for (const node of nodes) {\n if (node.type === 'directory') {\n allPaths.add(node.path);\n if (node.children) {\n collectPaths(node.children);\n }\n }\n }\n };\n collectPaths(rootNodes);\n setExpandedPaths(allPaths);\n }, [rootNodes]);\n\n // Collapse all directories\n const collapseAll = useCallback(() => {\n setExpandedPaths(new Set([rootPath]));\n }, [rootPath]);\n\n // Set selected file\n const setSelectedFile = useCallback((path: string | null) => {\n setSelectedFileState(path);\n // Add to query cache for quick access\n if (path) {\n queryClient.prefetchQuery({\n queryKey: fileExplorerKeys.content(path),\n queryFn: () => fetchFileContent(path),\n staleTime: CONTENT_STALE_TIME,\n });\n }\n }, [queryClient]);\n\n // Set view mode\n const setViewMode = useCallback((mode: ExplorerState['viewMode']) => {\n setViewModeState(mode);\n }, []);\n\n // Set sort order\n const setSortOrder = useCallback((order: ExplorerState['sortOrder']) => {\n setSortOrderState(order);\n }, []);\n\n // Toggle hidden files\n const toggleShowHidden = useCallback(() => {\n setShowHiddenFiles((prev) => !prev);\n }, []);\n\n // Set filter\n const setFilter = useCallback((value: string) => {\n setFilterState(value);\n }, []);\n\n // Load file content\n const loadFileContent = useCallback(async (path: string) => {\n try {\n const content = await queryClient.fetchQuery({\n queryKey: fileExplorerKeys.content(path),\n queryFn: () => fetchFileContent(path),\n staleTime: CONTENT_STALE_TIME,\n });\n return content;\n } catch (error) {\n console.error(`[useFileExplorer] Failed to load file content: ${path}`, error);\n throw error;\n }\n }, [queryClient]);\n\n // Search files\n const searchFilesHandler = useCallback(async (query: string) => {\n if (!query.trim()) {\n setSearchResults(undefined);\n return undefined;\n }\n try {\n const results = await queryClient.fetchQuery({\n queryKey: fileExplorerKeys.search(query),\n queryFn: () => searchFiles({ rootPath, query, maxResults: 100 }),\n staleTime: 60000, // 1 minute\n });\n setSearchResults(results);\n return results;\n } catch (error) {\n console.error('[useFileExplorer] Search failed:', error);\n throw error;\n }\n }, [queryClient, rootPath]);\n\n const isSearching = queryClient.isFetching({ queryKey: fileExplorerKeys.all }) > 0;\n\n // Clear file cache\n const clearFileCache = useCallback((path?: string) => {\n if (path) {\n queryClient.removeQueries({ queryKey: fileExplorerKeys.content(path) });\n } else {\n queryClient.removeQueries({ queryKey: fileExplorerKeys.contents() });\n }\n }, [queryClient]);\n\n // Refetch\n const refetch = async () => {\n await treeQuery.refetch();\n };\n\n // Build explorer state object\n const state: ExplorerState = {\n currentPath: rootPath,\n selectedFile,\n expandedPaths,\n fileTree: rootNodes,\n viewMode,\n sortOrder,\n showHiddenFiles,\n filter,\n isLoading: treeQuery.isLoading,\n error: treeQuery.error?.message ?? null,\n fileContents: {},\n recentFiles: [],\n maxRecentFiles: 10,\n directoriesFirst: true,\n };\n\n return {\n state,\n rootNodes,\n isLoading: treeQuery.isLoading,\n isFetching: treeQuery.isFetching,\n error: treeQuery.error,\n refetch,\n setSelectedFile,\n toggleExpanded,\n expandDirectory,\n collapseDirectory,\n expandAll,\n collapseAll,\n setViewMode,\n setSortOrder,\n toggleShowHidden,\n setFilter,\n loadFileContent,\n rootDirectories,\n isLoadingRoots: rootsQuery.isLoading,\n searchFiles: searchFilesHandler,\n searchResults,\n isSearching,\n clearFileCache,\n };\n}\n\n/**\n * Hook for file content with caching\n */\nexport function useFileContent(filePath: string | null, options: {\n enabled?: boolean;\n staleTime?: number;\n} = {}) {\n const { enabled = true, staleTime = CONTENT_STALE_TIME } = options;\n\n const query = useQuery({\n queryKey: fileExplorerKeys.content(filePath ?? ''),\n queryFn: () => fetchFileContent(filePath ?? ''),\n staleTime,\n enabled: enabled && !!filePath,\n retry: 1,\n });\n\n return {\n content: query.data,\n isLoading: query.isLoading,\n error: query.error,\n refetch: () => query.refetch(),\n };\n}\n\n/**\n * WebSocket hook for real-time file updates\n *\n * @example\n * ```tsx\n * const { isConnected } = useFileExplorerWebSocket({\n * onFileChanged: (path) => {\n * console.log('File changed:', path);\n * refetch();\n * }\n * });\n * ```\n */\nexport interface UseFileExplorerWebSocketOptions {\n /** Enable WebSocket connection */\n enabled?: boolean;\n /** Callback when file changes */\n onFileChanged?: (path: string) => void;\n /** Callback when directory changes */\n onDirectoryChanged?: (path: string) => void;\n}\n\nexport interface UseFileExplorerWebSocketReturn {\n /** WebSocket connection status */\n isConnected: boolean;\n}\n\nexport function useFileExplorerWebSocket(\n options: UseFileExplorerWebSocketOptions = {}\n): UseFileExplorerWebSocketReturn {\n const { enabled = true, onFileChanged, onDirectoryChanged } = options;\n const wsRef = useRef<WebSocket | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n\n useEffect(() => {\n if (!enabled) return;\n\n // Construct WebSocket URL\n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const wsUrl = `${protocol}//${window.location.host}/ws`;\n\n try {\n const ws = new WebSocket(wsUrl);\n wsRef.current = ws;\n\n ws.onopen = () => {\n console.log('[FileExplorerWS] Connected');\n setIsConnected(true);\n };\n\n ws.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data);\n\n // Handle file system change events\n if (data.type === 'FILE_CHANGED') {\n const { path } = data.payload || {};\n if (path) {\n onFileChanged?.(path);\n }\n } else if (data.type === 'DIRECTORY_CHANGED') {\n const { path } = data.payload || {};\n if (path) {\n onDirectoryChanged?.(path);\n }\n }\n } catch (error) {\n console.error('[FileExplorerWS] Failed to parse message:', error);\n }\n };\n\n ws.onclose = () => {\n console.log('[FileExplorerWS] Disconnected');\n setIsConnected(false);\n wsRef.current = null;\n };\n\n ws.onerror = (error) => {\n console.error('[FileExplorerWS] Error:', error);\n setIsConnected(false);\n };\n } catch (error) {\n console.error('[FileExplorerWS] Failed to connect:', error);\n }\n\n return () => {\n if (wsRef.current) {\n wsRef.current.close();\n wsRef.current = null;\n }\n };\n }, [enabled, onFileChanged, onDirectoryChanged]);\n\n return { isConnected };\n}\n\nexport default useFileExplorer;\n"],"names":["getFileIcon","fileName","ext","_a","codeExtensions","configExtensions","FileCode","File","formatFileSize","bytes","units","size","unitIndex","TreeNode","node","level","expandedPaths","selectedPath","maxDepth","showIcons","showSizes","onNodeClick","onNodeDoubleClick","onToggle","isDirectory","isExpanded","isSelected","hasChildren","shouldShowChildren","isAtMaxDepth","Icon","FolderOpen","Folder","handleClick","e","handleDoubleClick","handleKeyDown","jsxs","cn","jsx","ChevronRight","child","TreeView","nodes","depth","className","getLanguageDisplayName","language","getFileExtension","path","parts","isBinaryFile","binaryExtensions","truncateContent","content","maxLines","lines","FilePreview","fileContent","isLoading","error","maxSize","showLineNumbers","formatMessage","useIntl","copied","setCopied","React.useState","contentRef","React.useRef","handleCopy","err","Loader2","AlertCircle","isTooLarge","extension","truncatedContent","Button","Check","Copy","_","i","fileExplorerKeys","rootPath","query","TREE_STALE_TIME","CONTENT_STALE_TIME","useFileExplorer","options","excludePatterns","staleTime","enabled","queryClient","useQueryClient","setExpandedPaths","useState","selectedFile","setSelectedFileState","viewMode","setViewModeState","sortOrder","setSortOrderState","showHiddenFiles","setShowHiddenFiles","filter","setFilterState","searchResults","setSearchResults","treeQuery","useQuery","fetchFileTree","attemptIndex","rootsQuery","fetchRootDirectories","rootNodes","rootDirectories","toggleExpanded","useCallback","prev","next","expandDirectory","collapseDirectory","expandAll","allPaths","collectPaths","collapseAll","setSelectedFile","fetchFileContent","setViewMode","mode","setSortOrder","order","toggleShowHidden","setFilter","value","loadFileContent","searchFilesHandler","results","searchFiles","isSearching","clearFileCache","refetch","_b","useFileContent","filePath"],"mappings":"qOAmDA,SAASA,GAAYC,EAAqC,OACxD,MAAMC,GAAMC,EAAAF,EAAS,MAAM,GAAG,EAAE,IAAA,IAApB,YAAAE,EAA2B,cAEjCC,EAAiB,CAAC,KAAM,MAAO,KAAM,MAAO,MAAO,SAAU,KAAM,KAAM,KAAM,KAAM,OAAQ,KAAM,MAAO,QAAS,IAAI,EACvHC,EAAmB,CAAC,OAAQ,OAAQ,MAAO,OAAQ,MAAO,OAAQ,MAAO,QAAQ,EAEvF,OAAID,EAAe,SAASF,GAAO,EAAE,EAC5BI,EAELD,EAAiB,SAASH,GAAO,EAAE,EAC9BI,EAGFC,CACT,CAKA,SAASC,GAAeC,EAAwB,CAC9C,GAAI,CAACA,EAAO,MAAO,GACnB,MAAMC,EAAQ,CAAC,IAAK,KAAM,KAAM,IAAI,EACpC,IAAIC,EAAOF,EACPG,EAAY,EAEhB,KAAOD,GAAQ,MAAQC,EAAYF,EAAM,OAAS,GAChDC,GAAQ,KACRC,IAGF,MAAO,GAAGD,EAAK,QAAQ,CAAC,CAAC,GAAGD,EAAME,CAAS,CAAC,EAC9C,CAKA,SAASC,EAAS,CAChB,KAAAC,EACA,MAAAC,EACA,cAAAC,EACA,aAAAC,EACA,SAAAC,EAAW,EACX,UAAAC,EAAY,GACZ,UAAAC,EAAY,GACZ,YAAAC,EACA,kBAAAC,EACA,SAAAC,CACF,EAAkB,CAChB,MAAMC,EAAcV,EAAK,OAAS,YAC5BW,EAAaT,EAAc,IAAIF,EAAK,IAAI,EACxCY,EAAaT,IAAiBH,EAAK,KACnCa,EAAcH,GAAeV,EAAK,UAAYA,EAAK,SAAS,OAAS,EACrEc,EAAqBH,GAAcE,EACnCE,EAAeX,EAAW,GAAKH,GAASG,EAG9C,IAAIY,EAA0BvB,EAC1BiB,EACFM,EAAOL,EAAaM,GAAaC,EACxBb,IACTW,EAAO9B,GAAYc,EAAK,IAAI,GAI9B,MAAMmB,EAAeC,GAAwB,CAC3CA,EAAE,gBAAA,EACFb,GAAA,MAAAA,EAAcP,GAGVU,GAAeG,IACjBJ,GAAA,MAAAA,EAAWT,EAAK,MAEpB,EAGMqB,EAAqBD,GAAwB,CACjDA,EAAE,gBAAA,EACFZ,GAAA,MAAAA,EAAoBR,EACtB,EAGMsB,EAAiBF,GAA2B,EAC5CA,EAAE,MAAQ,SAAWA,EAAE,MAAQ,OACjCA,EAAE,eAAA,EACFD,EAAYC,CAAQ,EAExB,EAEA,OACEG,EAAAA,KAAC,MAAA,CACC,UAAWC,EACT,YACAd,GAAe,iBACfE,GAAc,UAAA,EAEhB,KAAK,WACL,gBAAeF,EAAcC,EAAa,OAC1C,gBAAeC,EAGf,SAAA,CAAAW,EAAAA,KAAC,MAAA,CACC,UAAWC,EACT,gFACA,uCACAZ,GAAc,6BACd,yBAAA,EAEF,MAAO,CAAE,YAAa,GAAGX,EAAQ,GAAK,CAAC,IAAA,EACvC,QAASkB,EACT,cAAeE,EACf,UAAWC,EACX,SAAU,EACV,MAAOtB,EAAK,KAGX,SAAA,CAAAU,GACCe,EAAAA,IAACC,GAAA,CACC,UAAWF,EACT,mEACAb,GAAc,WAAA,CAChB,CAAA,EAKHN,GACCoB,EAAAA,IAACT,EAAA,CACC,UAAWQ,EACT,wBACAd,EACIC,EACE,gBACA,gBACF,uBAAA,CACN,CAAA,EAKJc,EAAAA,IAAC,OAAA,CAAK,UAAU,kBAAmB,WAAK,KAAK,EAG5CzB,EAAK,aACJyB,EAAAA,IAAC,OAAA,CACC,UAAU,wFACV,MAAM,6BACP,SAAA,IAAA,CAAA,EAMFnB,GAAa,CAACI,GAAeV,EAAK,MACjCyB,EAAAA,IAAC,OAAA,CAAK,UAAU,wCACb,SAAA/B,GAAeM,EAAK,IAAI,CAAA,CAC3B,CAAA,CAAA,CAAA,EAKHc,GAAsB,CAACC,GAAgBf,EAAK,UAC3CyB,EAAAA,IAAC,MAAA,CAAI,UAAU,gBAAgB,KAAK,QACjC,SAAAzB,EAAK,SAAS,IAAK2B,GAClBF,EAAAA,IAAC1B,EAAA,CAEC,KAAM4B,EACN,MAAO1B,EAAQ,EACf,cAAAC,EACA,aAAAC,EACA,SAAAC,EACA,UAAAC,EACA,UAAAC,EACA,YAAAC,EACA,kBAAAC,EACA,SAAAC,CAAA,EAVKkB,EAAM,IAAA,CAYd,CAAA,CACH,CAAA,CAAA,CAAA,CAIR,CAkBO,SAASC,GAAS,CACvB,MAAAC,EACA,cAAA3B,EACA,aAAAC,EACA,YAAAI,EACA,kBAAAC,EACA,SAAAC,EACA,SAAAL,EAAW,EACX,MAAA0B,EAAQ,EACR,UAAAzB,EAAY,GACZ,UAAAC,EAAY,GACZ,UAAAyB,CACF,EAAkB,CAChB,OAAIF,EAAM,SAAW,EAEjBN,EAAAA,KAAC,MAAA,CAAI,UAAU,kEACb,SAAA,CAAAE,EAAAA,IAACP,EAAA,CAAO,UAAU,sCAAA,CAAuC,EACzDO,EAAAA,IAAC,IAAA,CAAE,UAAU,gCAAgC,SAAA,gBAAA,CAAc,CAAA,EAC7D,EAKFA,EAAAA,IAAC,MAAA,CACC,UAAWD,EAAG,YAAaO,CAAS,EACpC,KAAK,OACL,aAAW,YAEV,SAAAF,EAAM,IAAK7B,GACVyB,EAAAA,IAAC1B,EAAA,CAEC,KAAAC,EACA,MAAO8B,EACP,cAAA5B,EACA,aAAAC,EACA,SAAAC,EACA,UAAAC,EACA,UAAAC,EACA,YAAAC,EACA,kBAAAC,EACA,SAAAC,CAAA,EAVKT,EAAK,IAAA,CAYb,CAAA,CAAA,CAGP,CCzQA,SAASgC,GAAuBC,EAA2B,CACzD,OAAKA,EAEyC,CAC5C,WAAc,aACd,IAAO,iBACP,WAAc,aACd,IAAO,YACP,OAAU,SACV,KAAQ,OACR,GAAM,KACN,KAAQ,OACR,KAAQ,OACR,OAAU,KACV,IAAO,MACP,MAAS,QACT,OAAU,SACV,SAAY,WACZ,KAAQ,OACR,KAAQ,OACR,IAAO,MACP,KAAQ,OACR,IAAO,MACP,KAAQ,OACR,KAAQ,OACR,IAAO,MACP,KAAQ,OACR,KAAQ,YAAA,EAGWA,CAAQ,GAAKA,EAAS,OAAO,CAAC,EAAE,YAAA,EAAgBA,EAAS,MAAM,CAAC,EA7B/D,YA8BxB,CAKA,SAASC,EAAiBC,EAAsB,CAC9C,MAAMC,EAAQD,EAAK,MAAM,GAAG,EAC5B,OAAOC,EAAM,OAAS,EAAIA,EAAMA,EAAM,OAAS,CAAC,EAAI,EACtD,CAKA,SAASC,GAAaF,EAAuB,CAC3C,MAAMG,EAAmB,CACvB,MAAO,MAAO,OAAQ,MAAO,MAAO,MAAO,OAAQ,MACnD,MAAO,MAAO,OAAQ,MAAO,OAAQ,MAAO,OAC5C,MAAO,MAAO,KAAM,MAAO,KAC3B,MAAO,MAAO,MAAO,MAAO,MAC5B,MAAO,MAAO,OAAQ,QAAS,MAC/B,MAAO,MAAO,KAAM,QACpB,QAAS,MAAO,MAChB,MAAO,MAAO,GAAA,EAGVlD,EAAM8C,EAAiBC,CAAI,EAAE,YAAA,EACnC,OAAOG,EAAiB,SAASlD,CAAG,CACtC,CAKA,SAASM,EAAeC,EAAwB,CAC9C,GAAI,CAACA,EAAO,MAAO,GACnB,MAAMC,EAAQ,CAAC,IAAK,KAAM,KAAM,IAAI,EACpC,IAAIC,EAAOF,EACPG,EAAY,EAEhB,KAAOD,GAAQ,MAAQC,EAAYF,EAAM,OAAS,GAChDC,GAAQ,KACRC,IAGF,MAAO,GAAGD,EAAK,QAAQ,CAAC,CAAC,IAAID,EAAME,CAAS,CAAC,EAC/C,CAKA,SAASyC,GAAgBC,EAAiBC,EAAmB,IAAc,CACzE,MAAMC,EAAQF,EAAQ,MAAM;AAAA,CAAI,EAChC,OAAIE,EAAM,QAAUD,EAAiBD,EAE9BE,EAAM,MAAM,EAAGD,CAAQ,EAAE,KAAK;AAAA,CAAI,EAAI;AAAA;AAAA,OAAYC,EAAM,OAASD,CAAQ,cAClF,CAKO,SAASE,GAAY,CAC1B,YAAAC,EACA,UAAAC,EAAY,GACZ,MAAAC,EAAQ,KACR,UAAAf,EACA,QAAAgB,EAAU,KAAO,KACjB,gBAAAC,EAAkB,EACpB,EAAqB,CACnB,KAAM,CAAE,cAAAC,CAAA,EAAkBC,GAAA,EACpB,CAACC,EAAQC,CAAS,EAAIC,EAAAA,SAAe,EAAK,EAC1CC,EAAaC,EAAAA,OAA6B,IAAI,EAG9CC,EAAa,SAAY,CAC7B,GAAKZ,GAAA,MAAAA,EAAa,QAElB,GAAI,CACF,MAAM,UAAU,UAAU,UAAUA,EAAY,OAAO,EACvDQ,EAAU,EAAI,EACd,WAAW,IAAMA,EAAU,EAAK,EAAG,GAAI,CACzC,OAASK,EAAK,CACZ,QAAQ,MAAM,0BAA2BA,CAAG,CAC9C,CACF,EAGA,GAAIZ,EACF,cACG,MAAA,CAAI,UAAWrB,EAAG,yCAA0CO,CAAS,EACpE,SAAA,CAAAN,EAAAA,IAACiC,GAAA,CAAQ,UAAU,4CAAA,CAA6C,EAChEjC,MAAC,QAAK,UAAU,qCACb,WAAc,CAAE,GAAI,0BAAA,CAA4B,CAAA,CACnD,CAAA,EACF,EAKJ,GAAIqB,EACF,cACG,MAAA,CAAI,UAAWtB,EAAG,mEAAoEO,CAAS,EAC9F,SAAA,CAAAN,EAAAA,IAACkC,EAAA,CAAY,UAAU,iCAAA,CAAkC,EACzDlC,EAAAA,IAAC,MAAG,UAAU,2CACX,WAAc,CAAE,GAAI,6BAAA,CAA+B,EACtD,EACAA,EAAAA,IAAC,IAAA,CAAE,UAAU,yCAA0C,SAAAqB,CAAA,CAAM,CAAA,EAC/D,EAKJ,GAAI,CAACF,EACH,cACG,MAAA,CAAI,UAAWpB,EAAG,mEAAoEO,CAAS,EAC9F,SAAA,CAAAN,EAAAA,IAAChC,EAAA,CAAK,UAAU,sCAAA,CAAuC,EACvDgC,EAAAA,IAAC,MAAG,UAAU,2CACX,WAAc,CAAE,GAAI,6BAAA,CAA+B,EACtD,EACAA,MAAC,KAAE,UAAU,gCACV,WAAc,CAAE,GAAI,+BAAA,CAAiC,CAAA,CACxD,CAAA,EACF,EAKJ,MAAMmC,EAAab,EAAU,IAAMH,EAAY,MAAQ,GAAKG,EAI5D,GAHiBV,GAAaO,EAAY,IAAI,EAI5C,cACG,MAAA,CAAI,UAAWpB,EAAG,mEAAoEO,CAAS,EAC9F,SAAA,CAAAN,EAAAA,IAAChC,EAAA,CAAK,UAAU,sCAAA,CAAuC,EACvDgC,EAAAA,IAAC,MAAG,UAAU,2CACX,WAAc,CAAE,GAAI,8BAAA,CAAgC,EACvD,EACAA,EAAAA,IAAC,KAAE,UAAU,qCACV,WAAc,CAAE,GAAI,gCAAA,CAAkC,EACzD,EACAF,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAM,WAAY,IAAA,CAAK,EACvBmB,EAAY,MACXrB,OAAC,OAAA,CAAK,UAAU,OAAO,SAAA,CAAA,IAAE7B,EAAekD,EAAY,IAAI,EAAE,GAAA,CAAA,CAAC,CAAA,CAAA,CAE/D,CAAA,EACF,EAKJ,GAAIgB,EACF,cACG,MAAA,CAAI,UAAWpC,EAAG,mEAAoEO,CAAS,EAC9F,SAAA,CAAAN,EAAAA,IAACkC,EAAA,CAAY,UAAU,6BAAA,CAA8B,EACrDlC,EAAAA,IAAC,MAAG,UAAU,2CACX,WAAc,CAAE,GAAI,gCAAA,CAAkC,EACzD,EACAA,EAAAA,IAAC,IAAA,CAAE,UAAU,qCACV,SAAAwB,EACC,CAAE,GAAI,kCAAA,EACN,CAAE,KAAMvD,EAAeqD,CAAO,CAAA,CAAE,EAEpC,EACAxB,EAAAA,KAAC,MAAA,CAAI,UAAU,gCACb,SAAA,CAAAE,EAAAA,IAAC,OAAA,CAAM,WAAY,IAAA,CAAK,EACvBmB,EAAY,MACXrB,OAAC,OAAA,CAAK,UAAU,OAAO,SAAA,CAAA,IAAE7B,EAAekD,EAAY,IAAI,EAAE,GAAA,CAAA,CAAC,CAAA,CAAA,CAE/D,CAAA,EACF,EAKJ,MAAMzD,EAAWyD,EAAY,KAAK,MAAM,GAAG,EAAE,OAAS,GAChDiB,EAAY3B,EAAiBU,EAAY,IAAI,EAC7CX,EAAWW,EAAY,UAAYZ,GAAuBY,EAAY,QAAQ,EAC9EkB,EAAmBvB,GAAgBK,EAAY,OAAO,EAGtDF,EAAQoB,EAAiB,MAAM;AAAA,CAAI,EAEzC,cACG,MAAA,CAAI,UAAWtC,EAAG,oCAAqCO,CAAS,EAE/D,SAAA,CAAAR,EAAAA,KAAC,MAAA,CAAI,UAAU,iFACb,SAAA,CAAAA,EAAAA,KAAC,MAAA,CAAI,UAAU,yCACb,SAAA,CAAAE,EAAAA,IAAChC,EAAA,CAAK,UAAU,6CAAA,CAA8C,EAC9DgC,EAAAA,IAAC,OAAA,CAAK,UAAU,+BAAgC,SAAAtC,EAAS,EACxD0E,GACCtC,EAAAA,KAAC,OAAA,CAAK,UAAU,0CAA0C,SAAA,CAAA,IAAEsC,CAAA,EAAU,EAEvEjB,EAAY,MACXrB,OAAC,OAAA,CAAK,UAAU,gCAAgC,SAAA,CAAA,IAC5C7B,EAAekD,EAAY,IAAI,EAAE,GAAA,CAAA,CACrC,CAAA,EAEJ,EACArB,EAAAA,KAAC,MAAA,CAAI,UAAU,0BACZ,SAAA,CAAAqB,EAAY,UACXnB,EAAAA,IAAC,OAAA,CAAK,UAAU,6DACb,SAAAQ,EACH,EAEFR,EAAAA,IAACsC,GAAA,CACC,QAAQ,QACR,KAAK,KACL,UAAU,cACV,QAASP,EACT,MAAOP,EAAc,CAAE,GAAI,wBAAyB,EAEnD,SAAAE,QACEa,GAAA,CAAM,UAAU,uBAAuB,EAExCvC,EAAAA,IAACwC,GAAA,CAAK,UAAU,SAAA,CAAU,CAAA,CAAA,CAE9B,CAAA,CACF,CAAA,EACF,EAGAxC,EAAAA,IAAC,MAAA,CAAI,UAAU,wCACb,SAAAA,EAAAA,IAAC,MAAA,CACC,IAAK6B,EACL,UAAW9B,EACT,gCACA,4BACA,kCACA,4DAAA,EAGD,SAAAwB,EACCzB,OAAC,MAAA,CAAI,UAAU,OAEb,SAAA,CAAAE,MAAC,OAAI,UAAU,6FACZ,SAAAiB,EAAM,IAAI,CAACwB,EAAGC,IACb1C,EAAAA,IAAC,MAAA,CAAY,UAAU,kBACpB,SAAA0C,EAAI,CAAA,EADGA,CAEV,CACD,EACH,EAEA1C,EAAAA,IAAC,OAAA,CAAK,UAAU,SAAU,SAAAqC,CAAA,CAAiB,CAAA,CAAA,CAC7C,EAEArC,EAAAA,IAAC,OAAA,CAAM,SAAAqC,CAAA,CAAiB,CAAA,CAAA,EAG9B,EAGClB,EAAY,cACXnB,MAAC,MAAA,CAAI,UAAU,iEACZ,SAAAwB,EACC,CAAE,GAAI,+BAAA,EACN,CAAE,KAAM,IAAI,KAAKL,EAAY,YAAY,EAAE,gBAAe,CAAE,CAC9D,CACF,CAAA,EAEJ,CAEJ,CChTO,MAAMwB,EAAmB,CAC9B,IAAK,CAAC,cAAc,EACpB,MAAO,IAAM,CAAC,GAAGA,EAAiB,IAAK,MAAM,EAC7C,KAAOC,GAAqB,CAAC,GAAGD,EAAiB,MAAA,EAASC,CAAQ,EAClE,SAAU,IAAM,CAAC,GAAGD,EAAiB,IAAK,SAAS,EACnD,QAAUjC,GAAiB,CAAC,GAAGiC,EAAiB,SAAA,EAAYjC,CAAI,EAChE,MAAO,IAAM,CAAC,GAAGiC,EAAiB,IAAK,OAAO,EAC9C,OAASE,GAAkB,CAAC,GAAGF,EAAiB,IAAK,SAAUE,CAAK,CACtE,EAGMC,EAAkB,IAAS,IAE3BC,EAAqB,IAAU,IA4E9B,SAASC,GAAgBC,EAAkC,GAA2B,SAC3F,KAAM,CACJ,SAAAL,EAAW,IACX,SAAAjE,EAAW,EAEX,gBAAAuE,EACA,UAAAC,EACA,QAAAC,EAAU,EAAA,EACRH,EAEEI,EAAcC,GAAA,EAGd,CAAC7E,EAAe8E,CAAgB,EAAIC,EAAAA,aAA0B,IAAI,CAACZ,CAAQ,CAAC,CAAC,EAC7E,CAACa,EAAcC,CAAoB,EAAIF,EAAAA,SAAwB,IAAI,EACnE,CAACG,EAAUC,CAAgB,EAAIJ,EAAAA,SAAoC,MAAM,EACzE,CAACK,EAAWC,CAAiB,EAAIN,EAAAA,SAAqC,MAAM,EAC5E,CAACO,EAAiBC,CAAkB,EAAIR,EAAAA,SAAS,EAAK,EACtD,CAACS,EAAQC,CAAc,EAAIV,EAAAA,SAAS,EAAE,EACtC,CAACW,EAAeC,CAAgB,EAAIZ,WAAA,EAGpCa,EAAYC,EAAS,CACzB,SAAU,CAAC,GAAG3B,EAAiB,KAAKC,CAAQ,EAAG,CAAE,WAAYmB,EAAiB,EAC9E,QAAS,IAAMQ,GAAc3B,EAAU,CAAE,SAAAjE,EAAU,cAAeoF,EAAiB,gBAAAb,EAAiB,EACpG,UAAWC,GAAaL,EACxB,QAAAM,EACA,MAAO,EACP,WAAaoB,GAAiB,KAAK,IAAI,IAAO,GAAKA,EAAc,GAAK,CAAA,CACvE,EAGKC,EAAaH,EAAS,CAC1B,SAAU3B,EAAiB,MAAA,EAC3B,QAAS+B,GACT,UAAW5B,EACX,QAAAM,EACA,MAAO,CAAA,CACR,EAEKuB,IAAY/G,EAAAyG,EAAU,OAAV,YAAAzG,EAAgB,YAAa,CAAA,EACzCgH,EAAkBH,EAAW,KAG7BI,EAAiBC,cAAapE,GAAiB,CACnD6C,EAAkBwB,GAAS,CACzB,MAAMC,EAAO,IAAI,IAAID,CAAI,EACzB,OAAIC,EAAK,IAAItE,CAAI,EACfsE,EAAK,OAAOtE,CAAI,EAEhBsE,EAAK,IAAItE,CAAI,EAERsE,CACT,CAAC,CACH,EAAG,CAAA,CAAE,EAGCC,EAAkBH,cAAapE,GAAiB,CACpD6C,EAAkBwB,GAAS,IAAI,IAAI,CAAC,GAAGA,EAAMrE,CAAI,CAAC,CAAC,CACrD,EAAG,CAAA,CAAE,EAGCwE,EAAoBJ,cAAapE,GAAiB,CACtD6C,EAAkBwB,GAAS,CACzB,MAAMC,EAAO,IAAI,IAAID,CAAI,EACzB,OAAAC,EAAK,OAAOtE,CAAI,EACTsE,CACT,CAAC,CACH,EAAG,CAAA,CAAE,EAGCG,EAAYL,EAAAA,YAAY,IAAM,CAClC,MAAMM,MAAe,IACfC,EAAgBjF,GAA4B,CAChD,UAAW7B,KAAQ6B,EACb7B,EAAK,OAAS,cAChB6G,EAAS,IAAI7G,EAAK,IAAI,EAClBA,EAAK,UACP8G,EAAa9G,EAAK,QAAQ,EAIlC,EACA8G,EAAaV,CAAS,EACtBpB,EAAiB6B,CAAQ,CAC3B,EAAG,CAACT,CAAS,CAAC,EAGRW,EAAcR,EAAAA,YAAY,IAAM,CACpCvB,EAAiB,IAAI,IAAI,CAACX,CAAQ,CAAC,CAAC,CACtC,EAAG,CAACA,CAAQ,CAAC,EAGP2C,EAAkBT,cAAapE,GAAwB,CAC3DgD,EAAqBhD,CAAI,EAErBA,GACF2C,EAAY,cAAc,CACxB,SAAUV,EAAiB,QAAQjC,CAAI,EACvC,QAAS,IAAM8E,EAAiB9E,CAAI,EACpC,UAAWqC,CAAA,CACZ,CAEL,EAAG,CAACM,CAAW,CAAC,EAGVoC,EAAcX,cAAaY,GAAoC,CACnE9B,EAAiB8B,CAAI,CACvB,EAAG,CAAA,CAAE,EAGCC,EAAeb,cAAac,GAAsC,CACtE9B,EAAkB8B,CAAK,CACzB,EAAG,CAAA,CAAE,EAGCC,GAAmBf,EAAAA,YAAY,IAAM,CACzCd,EAAoBe,GAAS,CAACA,CAAI,CACpC,EAAG,CAAA,CAAE,EAGCe,GAAYhB,cAAaiB,GAAkB,CAC/C7B,EAAe6B,CAAK,CACtB,EAAG,CAAA,CAAE,EAGCC,GAAkBlB,cAAY,MAAOpE,GAAiB,CAC1D,GAAI,CAMF,OALgB,MAAM2C,EAAY,WAAW,CAC3C,SAAUV,EAAiB,QAAQjC,CAAI,EACvC,QAAS,IAAM8E,EAAiB9E,CAAI,EACpC,UAAWqC,CAAA,CACZ,CAEH,OAAS1B,EAAO,CACd,cAAQ,MAAM,kDAAkDX,CAAI,GAAIW,CAAK,EACvEA,CACR,CACF,EAAG,CAACgC,CAAW,CAAC,EAGV4C,GAAqBnB,cAAY,MAAOjC,GAAkB,CAC9D,GAAI,CAACA,EAAM,OAAQ,CACjBuB,EAAiB,MAAS,EAC1B,MACF,CACA,GAAI,CACF,MAAM8B,EAAU,MAAM7C,EAAY,WAAW,CAC3C,SAAUV,EAAiB,OAAOE,CAAK,EACvC,QAAS,IAAMsD,GAAY,CAAE,SAAAvD,EAAU,MAAAC,EAAO,WAAY,IAAK,EAC/D,UAAW,GAAA,CACZ,EACD,OAAAuB,EAAiB8B,CAAO,EACjBA,CACT,OAAS7E,EAAO,CACd,cAAQ,MAAM,mCAAoCA,CAAK,EACjDA,CACR,CACF,EAAG,CAACgC,EAAaT,CAAQ,CAAC,EAEpBwD,GAAc/C,EAAY,WAAW,CAAE,SAAUV,EAAiB,GAAA,CAAK,EAAI,EAG3E0D,GAAiBvB,cAAapE,GAAkB,CAChDA,EACF2C,EAAY,cAAc,CAAE,SAAUV,EAAiB,QAAQjC,CAAI,EAAG,EAEtE2C,EAAY,cAAc,CAAE,SAAUV,EAAiB,SAAA,EAAY,CAEvE,EAAG,CAACU,CAAW,CAAC,EAGViD,GAAU,SAAY,CAC1B,MAAMjC,EAAU,QAAA,CAClB,EAoBA,MAAO,CACL,MAlB2B,CAC3B,YAAazB,EACb,aAAAa,EACA,cAAAhF,EACA,SAAUkG,EACV,SAAAhB,EACA,UAAAE,EACA,gBAAAE,EACA,OAAAE,EACA,UAAWI,EAAU,UACrB,QAAOkC,EAAAlC,EAAU,QAAV,YAAAkC,EAAiB,UAAW,KACnC,aAAc,CAAA,EACd,YAAa,CAAA,EACb,eAAgB,GAChB,iBAAkB,EAAA,EAKlB,UAAA5B,EACA,UAAWN,EAAU,UACrB,WAAYA,EAAU,WACtB,MAAOA,EAAU,MACjB,QAAAiC,GACA,gBAAAf,EACA,eAAAV,EACA,gBAAAI,EACA,kBAAAC,EACA,UAAAC,EACA,YAAAG,EACA,YAAAG,EACA,aAAAE,EACA,iBAAAE,GACA,UAAAC,GACA,gBAAAE,GACA,gBAAApB,EACA,eAAgBH,EAAW,UAC3B,YAAawB,GACb,cAAA9B,EACA,YAAAiC,GACA,eAAAC,EAAA,CAEJ,CAKO,SAASG,GAAeC,EAAyBxD,EAGpD,GAAI,CACN,KAAM,CAAE,QAAAG,EAAU,GAAM,UAAAD,EAAYJ,GAAuBE,EAErDJ,EAAQyB,EAAS,CACrB,SAAU3B,EAAiB,QAAQ8D,GAAY,EAAE,EACjD,QAAS,IAAMjB,EAAiBiB,GAAY,EAAE,EAC9C,UAAAtD,EACA,QAASC,GAAW,CAAC,CAACqD,EACtB,MAAO,CAAA,CACR,EAED,MAAO,CACL,QAAS5D,EAAM,KACf,UAAWA,EAAM,UACjB,MAAOA,EAAM,MACb,QAAS,IAAMA,EAAM,QAAA,CAAQ,CAEjC"}
|
|
1
|
+
{"version":3,"file":"useFileExplorer-DOmpm6v9.js","sources":["../../src/components/shared/TreeView.tsx","../../src/components/shared/FilePreview.tsx","../../src/hooks/useFileExplorer.ts"],"sourcesContent":["// ========================================\n// TreeView Component\n// ========================================\n// Recursive tree view component for file explorer using native HTML details/summary\n\nimport * as React from 'react';\nimport { ChevronRight, File, Folder, FolderOpen, FileCode } from 'lucide-react';\nimport { cn } from '@/lib/utils';\nimport type { FileSystemNode } from '@/types/file-explorer';\n\nexport interface TreeViewProps {\n /** Root nodes of the file tree */\n nodes: FileSystemNode[];\n /** Set of expanded directory paths */\n expandedPaths: Set<string>;\n /** Currently selected file path */\n selectedPath: string | null;\n /** Callback when node is clicked */\n onNodeClick?: (node: FileSystemNode) => void;\n /** Callback when node is double-clicked */\n onNodeDoubleClick?: (node: FileSystemNode) => void;\n /** Callback to toggle expanded state */\n onToggle?: (path: string) => void;\n /** Maximum depth to display (0 = unlimited) */\n maxDepth?: number;\n /** Current depth level */\n depth?: number;\n /** Whether to show file icons */\n showIcons?: boolean;\n /** Whether to show file sizes */\n showSizes?: boolean;\n /** Custom class name */\n className?: string;\n}\n\ninterface TreeNodeProps {\n node: FileSystemNode;\n level: number;\n expandedPaths: Set<string>;\n selectedPath: string | null;\n maxDepth?: number;\n showIcons?: boolean;\n showSizes?: boolean;\n onNodeClick?: (node: FileSystemNode) => void;\n onNodeDoubleClick?: (node: FileSystemNode) => void;\n onToggle?: (path: string) => void;\n}\n\n/**\n * Get file icon based on file extension\n */\nfunction getFileIcon(fileName: string): React.ElementType {\n const ext = fileName.split('.').pop()?.toLowerCase();\n \n const codeExtensions = ['ts', 'tsx', 'js', 'jsx', 'vue', 'svelte', 'py', 'rb', 'go', 'rs', 'java', 'cs', 'php', 'scala', 'kt'];\n const configExtensions = ['json', 'yaml', 'yml', 'toml', 'ini', 'conf', 'xml', 'config'];\n \n if (codeExtensions.includes(ext || '')) {\n return FileCode;\n }\n if (configExtensions.includes(ext || '')) {\n return FileCode;\n }\n \n return File;\n}\n\n/**\n * Get file size in human-readable format\n */\nfunction formatFileSize(bytes?: number): string {\n if (!bytes) return '';\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unitIndex = 0;\n \n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n \n return `${size.toFixed(1)}${units[unitIndex]}`;\n}\n\n/**\n * TreeNode component - renders a single tree node with children\n */\nfunction TreeNode({\n node,\n level,\n expandedPaths,\n selectedPath,\n maxDepth = 0,\n showIcons = true,\n showSizes = false,\n onNodeClick,\n onNodeDoubleClick,\n onToggle,\n}: TreeNodeProps) {\n const isDirectory = node.type === 'directory';\n const isExpanded = expandedPaths.has(node.path);\n const isSelected = selectedPath === node.path;\n const hasChildren = isDirectory && node.children && node.children.length > 0;\n const shouldShowChildren = isExpanded && hasChildren;\n const isAtMaxDepth = maxDepth > 0 && level >= maxDepth;\n\n // Get icon component\n let Icon: React.ElementType = File;\n if (isDirectory) {\n Icon = isExpanded ? FolderOpen : Folder;\n } else if (showIcons) {\n Icon = getFileIcon(node.name);\n }\n\n // Handle click\n const handleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onNodeClick?.(node);\n \n // Toggle directories on click\n if (isDirectory && hasChildren) {\n onToggle?.(node.path);\n }\n };\n\n // Handle double click\n const handleDoubleClick = (e: React.MouseEvent) => {\n e.stopPropagation();\n onNodeDoubleClick?.(node);\n };\n\n // Handle key press for accessibility\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === 'Enter' || e.key === ' ') {\n e.preventDefault();\n handleClick(e as any);\n }\n };\n\n return (\n <div\n className={cn(\n 'tree-node',\n isDirectory && 'tree-directory',\n isSelected && 'selected'\n )}\n role=\"treeitem\"\n aria-expanded={isDirectory ? isExpanded : undefined}\n aria-selected={isSelected}\n >\n {/* Node content */}\n <div\n className={cn(\n 'flex items-center gap-1 px-2 py-1 rounded-sm cursor-pointer transition-colors',\n 'hover:bg-hover hover:text-foreground',\n isSelected && 'bg-primary/10 text-primary',\n 'text-foreground text-sm'\n )}\n style={{ paddingLeft: `${level * 16 + 8}px` }}\n onClick={handleClick}\n onDoubleClick={handleDoubleClick}\n onKeyDown={handleKeyDown}\n tabIndex={0}\n title={node.path}\n >\n {/* Expand/collapse chevron for directories */}\n {isDirectory && (\n <ChevronRight\n className={cn(\n 'h-4 w-4 flex-shrink-0 text-muted-foreground transition-transform',\n isExpanded && 'rotate-90'\n )}\n />\n )}\n \n {/* Folder/File icon */}\n {showIcons && (\n <Icon\n className={cn(\n 'h-4 w-4 flex-shrink-0',\n isDirectory\n ? isExpanded\n ? 'text-blue-500'\n : 'text-blue-400'\n : 'text-muted-foreground'\n )}\n />\n )}\n\n {/* Node name */}\n <span className=\"flex-1 truncate\">{node.name}</span>\n\n {/* CLAUDE.md indicator */}\n {node.hasClaudeMd && (\n <span\n className=\"ml-1 px-1.5 py-0.5 text-[10px] font-semibold rounded bg-purple-500/20 text-purple-500\"\n title=\"Contains CLAUDE.md context\"\n >\n MD\n </span>\n )}\n\n {/* File size */}\n {showSizes && !isDirectory && node.size && (\n <span className=\"text-xs text-muted-foreground ml-auto\">\n {formatFileSize(node.size)}\n </span>\n )}\n </div>\n\n {/* Recursive children */}\n {shouldShowChildren && !isAtMaxDepth && node.children && (\n <div className=\"tree-children\" role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.path}\n node={child}\n level={level + 1}\n expandedPaths={expandedPaths}\n selectedPath={selectedPath}\n maxDepth={maxDepth}\n showIcons={showIcons}\n showSizes={showSizes}\n onNodeClick={onNodeClick}\n onNodeDoubleClick={onNodeDoubleClick}\n onToggle={onToggle}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n\n/**\n * TreeView component - displays file tree with expand/collapse\n *\n * @example\n * ```tsx\n * <TreeView\n * nodes={fileTree}\n * expandedPaths={expandedPaths}\n * selectedPath={selectedFile}\n * onNodeClick={(node) => console.log('Clicked:', node.path)}\n * onToggle={(path) => toggleExpanded(path)}\n * showIcons\n * showSizes\n * />\n * ```\n */\nexport function TreeView({\n nodes,\n expandedPaths,\n selectedPath,\n onNodeClick,\n onNodeDoubleClick,\n onToggle,\n maxDepth = 0,\n depth = 0,\n showIcons = true,\n showSizes = false,\n className,\n}: TreeViewProps) {\n if (nodes.length === 0) {\n return (\n <div className=\"flex flex-col items-center justify-center py-8 px-4 text-center\">\n <Folder className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <p className=\"text-sm text-muted-foreground\">No files found</p>\n </div>\n );\n }\n\n return (\n <div\n className={cn('tree-view', className)}\n role=\"tree\"\n aria-label=\"File tree\"\n >\n {nodes.map((node) => (\n <TreeNode\n key={node.path}\n node={node}\n level={depth}\n expandedPaths={expandedPaths}\n selectedPath={selectedPath}\n maxDepth={maxDepth}\n showIcons={showIcons}\n showSizes={showSizes}\n onNodeClick={onNodeClick}\n onNodeDoubleClick={onNodeDoubleClick}\n onToggle={onToggle}\n />\n ))}\n </div>\n );\n}\n\nexport default TreeView;\n","// ========================================\n// FilePreview Component\n// ========================================\n// File content preview with syntax highlighting\n\nimport * as React from 'react';\nimport { File, Copy, Check, AlertCircle, Loader2 } from 'lucide-react';\nimport { useIntl } from 'react-intl';\nimport { cn } from '@/lib/utils';\nimport { Button } from '@/components/ui/Button';\nimport type { FileContent } from '@/types/file-explorer';\n\nexport interface FilePreviewProps {\n /** File content to display */\n fileContent: FileContent | null | undefined;\n /** Loading state */\n isLoading?: boolean;\n /** Error message */\n error?: string | null;\n /** Custom class name */\n className?: string;\n /** Maximum file size to preview in bytes */\n maxSize?: number;\n /** Whether to show line numbers */\n showLineNumbers?: boolean;\n}\n\n/**\n * Get language display name\n */\nfunction getLanguageDisplayName(language?: string): string {\n if (!language) return 'Plain Text';\n \n const languageNames: Record<string, string> = {\n 'typescript': 'TypeScript',\n 'tsx': 'TypeScript JSX',\n 'javascript': 'JavaScript',\n 'jsx': 'React JSX',\n 'python': 'Python',\n 'ruby': 'Ruby',\n 'go': 'Go',\n 'rust': 'Rust',\n 'java': 'Java',\n 'csharp': 'C#',\n 'php': 'PHP',\n 'scala': 'Scala',\n 'kotlin': 'Kotlin',\n 'markdown': 'Markdown',\n 'json': 'JSON',\n 'yaml': 'YAML',\n 'xml': 'XML',\n 'html': 'HTML',\n 'css': 'CSS',\n 'scss': 'SCSS',\n 'less': 'Less',\n 'sql': 'SQL',\n 'bash': 'Bash',\n 'text': 'Plain Text',\n };\n \n return languageNames[language] || language.charAt(0).toUpperCase() + language.slice(1);\n}\n\n/**\n * Get file extension from path\n */\nfunction getFileExtension(path: string): string {\n const parts = path.split('.');\n return parts.length > 1 ? parts[parts.length - 1] : '';\n}\n\n/**\n * Check if file is likely binary\n */\nfunction isBinaryFile(path: string): boolean {\n const binaryExtensions = [\n 'png', 'jpg', 'jpeg', 'gif', 'bmp', 'ico', 'webp', 'svg',\n 'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx',\n 'zip', 'tar', 'gz', 'rar', '7z',\n 'mp3', 'mp4', 'avi', 'mov', 'wav',\n 'ttf', 'otf', 'woff', 'woff2', 'eot',\n 'exe', 'dll', 'so', 'dylib',\n 'class', 'jar', 'war',\n 'pdb', 'obj', 'o',\n ];\n \n const ext = getFileExtension(path).toLowerCase();\n return binaryExtensions.includes(ext);\n}\n\n/**\n * Format file size for display\n */\nfunction formatFileSize(bytes?: number): string {\n if (!bytes) return '';\n const units = ['B', 'KB', 'MB', 'GB'];\n let size = bytes;\n let unitIndex = 0;\n \n while (size >= 1024 && unitIndex < units.length - 1) {\n size /= 1024;\n unitIndex++;\n }\n \n return `${size.toFixed(1)} ${units[unitIndex]}`;\n}\n\n/**\n * Truncate content if too large\n */\nfunction truncateContent(content: string, maxLines: number = 1000): string {\n const lines = content.split('\\n');\n if (lines.length <= maxLines) return content;\n \n return lines.slice(0, maxLines).join('\\n') + `\\n\\n... (${lines.length - maxLines} more lines)`;\n}\n\n/**\n * FilePreview component\n */\nexport function FilePreview({\n fileContent,\n isLoading = false,\n error = null,\n className,\n maxSize = 1024 * 1024, // 1MB default\n showLineNumbers = true,\n}: FilePreviewProps) {\n const { formatMessage } = useIntl();\n const [copied, setCopied] = React.useState(false);\n const contentRef = React.useRef<HTMLPreElement>(null);\n\n // Copy content to clipboard\n const handleCopy = async () => {\n if (!fileContent?.content) return;\n \n try {\n await navigator.clipboard.writeText(fileContent.content);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.error('Failed to copy content:', err);\n }\n };\n\n // Loading state\n if (isLoading) {\n return (\n <div className={cn('flex items-center justify-center py-12', className)}>\n <Loader2 className=\"h-8 w-8 animate-spin text-muted-foreground\" />\n <span className=\"ml-3 text-sm text-muted-foreground\">\n {formatMessage({ id: 'explorer.preview.loading' })}\n </span>\n </div>\n );\n }\n\n // Error state\n if (error) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <AlertCircle className=\"h-12 w-12 text-destructive mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.errorTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground max-w-md\">{error}</p>\n </div>\n );\n }\n\n // Empty state\n if (!fileContent) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <File className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.emptyTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground\">\n {formatMessage({ id: 'explorer.preview.emptyMessage' })}\n </p>\n </div>\n );\n }\n\n // Check if file is too large\n const isTooLarge = maxSize > 0 && (fileContent.size || 0) > maxSize;\n const isBinary = isBinaryFile(fileContent.path);\n\n // Binary file warning\n if (isBinary) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <File className=\"h-12 w-12 text-muted-foreground mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.binaryTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground mb-4\">\n {formatMessage({ id: 'explorer.preview.binaryMessage' })}\n </p>\n <div className=\"text-xs text-muted-foreground\">\n <span>{fileContent.path}</span>\n {fileContent.size && (\n <span className=\"ml-2\">({formatFileSize(fileContent.size)})</span>\n )}\n </div>\n </div>\n );\n }\n\n // File too large warning\n if (isTooLarge) {\n return (\n <div className={cn('flex flex-col items-center justify-center py-12 px-4 text-center', className)}>\n <AlertCircle className=\"h-12 w-12 text-warning mb-3\" />\n <h3 className=\"text-sm font-medium text-foreground mb-1\">\n {formatMessage({ id: 'explorer.preview.tooLargeTitle' })}\n </h3>\n <p className=\"text-xs text-muted-foreground mb-4\">\n {formatMessage(\n { id: 'explorer.preview.tooLargeMessage' },\n { size: formatFileSize(maxSize) }\n )}\n </p>\n <div className=\"text-xs text-muted-foreground\">\n <span>{fileContent.path}</span>\n {fileContent.size && (\n <span className=\"ml-2\">({formatFileSize(fileContent.size)})</span>\n )}\n </div>\n </div>\n );\n }\n\n // Get file name and extension\n const fileName = fileContent.path.split('/').pop() || '';\n const extension = getFileExtension(fileContent.path);\n const language = fileContent.language || getLanguageDisplayName(fileContent.language);\n const truncatedContent = truncateContent(fileContent.content);\n\n // Split into lines for line numbers\n const lines = truncatedContent.split('\\n');\n\n return (\n <div className={cn('file-preview flex flex-col h-full', className)}>\n {/* Preview header */}\n <div className=\"flex items-center justify-between px-4 py-2 border-b border-border bg-muted/30\">\n <div className=\"flex items-center gap-2 min-w-0 flex-1\">\n <File className=\"h-4 w-4 text-muted-foreground flex-shrink-0\" />\n <span className=\"text-sm font-medium truncate\">{fileName}</span>\n {extension && (\n <span className=\"text-xs text-muted-foreground uppercase\">.{extension}</span>\n )}\n {fileContent.size && (\n <span className=\"text-xs text-muted-foreground\">\n ({formatFileSize(fileContent.size)})\n </span>\n )}\n </div>\n <div className=\"flex items-center gap-2\">\n {fileContent.language && (\n <span className=\"text-xs text-muted-foreground px-2 py-0.5 rounded bg-muted\">\n {language}\n </span>\n )}\n <Button\n variant=\"ghost\"\n size=\"sm\"\n className=\"h-7 w-7 p-0\"\n onClick={handleCopy}\n title={formatMessage({ id: 'explorer.preview.copy' })}\n >\n {copied ? (\n <Check className=\"h-4 w-4 text-success\" />\n ) : (\n <Copy className=\"h-4 w-4\" />\n )}\n </Button>\n </div>\n </div>\n\n {/* Content area */}\n <div className=\"flex-1 overflow-auto custom-scrollbar\">\n <pre\n ref={contentRef}\n className={cn(\n 'text-sm p-4 m-0 bg-background',\n 'font-mono leading-relaxed',\n 'whitespace-pre-wrap break-words',\n '[&_::selection]:bg-primary/20 [&_::selection]:text-primary'\n )}\n >\n {showLineNumbers ? (\n <div className=\"flex\">\n {/* Line numbers */}\n <div className=\"text-right text-muted-foreground select-none pr-4 border-r border-border mr-4 min-w-[3rem]\">\n {lines.map((_, i) => (\n <div key={i} className=\"leading-relaxed\">\n {i + 1}\n </div>\n ))}\n </div>\n {/* Code content */}\n <code className=\"flex-1\">{truncatedContent}</code>\n </div>\n ) : (\n <code>{truncatedContent}</code>\n )}\n </pre>\n </div>\n\n {/* Footer with metadata */}\n {fileContent.modifiedTime && (\n <div className=\"px-4 py-2 border-t border-border text-xs text-muted-foreground\">\n {formatMessage(\n { id: 'explorer.preview.lastModified' },\n { time: new Date(fileContent.modifiedTime).toLocaleString() }\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport default FilePreview;\n","// ========================================\n// useFileExplorer Hook\n// ========================================\n// TanStack Query hooks for File Explorer with WebSocket subscription\n\nimport { useQuery, useQueryClient } from '@tanstack/react-query';\nimport { useState, useCallback, useEffect, useRef } from 'react';\nimport {\n fetchFileTree,\n fetchFileContent,\n fetchRootDirectories,\n searchFiles,\n type RootDirectory,\n type SearchFilesResponse,\n} from '../lib/api';\nimport type { FileSystemNode, FileContent, ExplorerState } from '../types/file-explorer';\n\n// Query key factory\nexport const fileExplorerKeys = {\n all: ['fileExplorer'] as const,\n trees: () => [...fileExplorerKeys.all, 'tree'] as const,\n tree: (rootPath: string) => [...fileExplorerKeys.trees(), rootPath] as const,\n contents: () => [...fileExplorerKeys.all, 'content'] as const,\n content: (path: string) => [...fileExplorerKeys.contents(), path] as const,\n roots: () => [...fileExplorerKeys.all, 'roots'] as const,\n search: (query: string) => [...fileExplorerKeys.all, 'search', query] as const,\n};\n\n// Default stale time: 5 minutes for file tree (stable structure)\nconst TREE_STALE_TIME = 5 * 60 * 1000;\n// Default stale time: 10 minutes for file content\nconst CONTENT_STALE_TIME = 10 * 60 * 1000;\n\nexport interface UseFileExplorerOptions {\n /** Root directory path (default: '/') */\n rootPath?: string;\n /** Maximum tree depth (0 = unlimited) */\n maxDepth?: number;\n /** Include hidden files */\n includeHidden?: boolean;\n /** File patterns to exclude (glob patterns) */\n excludePatterns?: string[];\n /** Override default stale time (ms) */\n staleTime?: number;\n /** Enable/disable the query */\n enabled?: boolean;\n}\n\nexport interface UseFileExplorerReturn {\n /** Current explorer state */\n state: ExplorerState;\n /** Root nodes of the file tree */\n rootNodes: FileSystemNode[];\n /** Loading state for initial fetch */\n isLoading: boolean;\n /** Fetching state (initial or refetch) */\n isFetching: boolean;\n /** Error object if query failed */\n error: Error | null;\n /** Manually refetch file tree */\n refetch: () => Promise<void>;\n /** Set the selected file path */\n setSelectedFile: (path: string | null) => void;\n /** Toggle directory expanded state */\n toggleExpanded: (path: string) => void;\n /** Expand a directory */\n expandDirectory: (path: string) => void;\n /** Collapse a directory */\n collapseDirectory: (path: string) => void;\n /** Expand all directories */\n expandAll: () => void;\n /** Collapse all directories */\n collapseAll: () => void;\n /** Set view mode */\n setViewMode: (mode: ExplorerState['viewMode']) => void;\n /** Set sort order */\n setSortOrder: (order: ExplorerState['sortOrder']) => void;\n /** Toggle hidden files visibility */\n toggleShowHidden: () => void;\n /** Set filter string */\n setFilter: (filter: string) => void;\n /** Load file content */\n loadFileContent: (path: string) => Promise<FileContent | undefined>;\n /** Available root directories */\n rootDirectories: RootDirectory[] | undefined;\n /** Root directories loading state */\n isLoadingRoots: boolean;\n /** Search files */\n searchFiles: (query: string) => Promise<SearchFilesResponse | undefined>;\n /** Search results */\n searchResults: SearchFilesResponse | undefined;\n /** Is searching */\n isSearching: boolean;\n /** Clear file content cache */\n clearFileCache: (path?: string) => void;\n}\n\n/**\n * Hook for File Explorer with WebSocket subscription for real-time updates\n *\n * @example\n * ```tsx\n * const { rootNodes, state, setSelectedFile, toggleExpanded } = useFileExplorer({\n * rootPath: '/src'\n * });\n * ```\n */\nexport function useFileExplorer(options: UseFileExplorerOptions = {}): UseFileExplorerReturn {\n const {\n rootPath = '/',\n maxDepth = 5,\n // includeHidden is now controlled by internal showHiddenFiles state\n excludePatterns,\n staleTime,\n enabled = true,\n } = options;\n\n const queryClient = useQueryClient();\n\n // Explorer state\n const [expandedPaths, setExpandedPaths] = useState<Set<string>>(new Set([rootPath]));\n const [selectedFile, setSelectedFileState] = useState<string | null>(null);\n const [viewMode, setViewModeState] = useState<ExplorerState['viewMode']>('tree');\n const [sortOrder, setSortOrderState] = useState<ExplorerState['sortOrder']>('name');\n const [showHiddenFiles, setShowHiddenFiles] = useState(false);\n const [filter, setFilterState] = useState('');\n const [searchResults, setSearchResults] = useState<SearchFilesResponse | undefined>();\n\n // Fetch file tree - use showHiddenFiles state instead of options.includeHidden\n const treeQuery = useQuery({\n queryKey: [...fileExplorerKeys.tree(rootPath), { showHidden: showHiddenFiles }],\n queryFn: () => fetchFileTree(rootPath, { maxDepth, includeHidden: showHiddenFiles, excludePatterns }),\n staleTime: staleTime ?? TREE_STALE_TIME,\n enabled,\n retry: 2,\n retryDelay: (attemptIndex) => Math.min(1000 * 2 ** attemptIndex, 10000),\n });\n\n // Fetch root directories\n const rootsQuery = useQuery({\n queryKey: fileExplorerKeys.roots(),\n queryFn: fetchRootDirectories,\n staleTime: TREE_STALE_TIME,\n enabled,\n retry: 1,\n });\n\n const rootNodes = treeQuery.data?.rootNodes ?? [];\n const rootDirectories = rootsQuery.data;\n\n // Toggle expanded state\n const toggleExpanded = useCallback((path: string) => {\n setExpandedPaths((prev) => {\n const next = new Set(prev);\n if (next.has(path)) {\n next.delete(path);\n } else {\n next.add(path);\n }\n return next;\n });\n }, []);\n\n // Expand directory\n const expandDirectory = useCallback((path: string) => {\n setExpandedPaths((prev) => new Set([...prev, path]));\n }, []);\n\n // Collapse directory\n const collapseDirectory = useCallback((path: string) => {\n setExpandedPaths((prev) => {\n const next = new Set(prev);\n next.delete(path);\n return next;\n });\n }, []);\n\n // Expand all directories\n const expandAll = useCallback(() => {\n const allPaths = new Set<string>();\n const collectPaths = (nodes: FileSystemNode[]) => {\n for (const node of nodes) {\n if (node.type === 'directory') {\n allPaths.add(node.path);\n if (node.children) {\n collectPaths(node.children);\n }\n }\n }\n };\n collectPaths(rootNodes);\n setExpandedPaths(allPaths);\n }, [rootNodes]);\n\n // Collapse all directories\n const collapseAll = useCallback(() => {\n setExpandedPaths(new Set([rootPath]));\n }, [rootPath]);\n\n // Set selected file\n const setSelectedFile = useCallback((path: string | null) => {\n setSelectedFileState(path);\n // Add to query cache for quick access\n if (path) {\n queryClient.prefetchQuery({\n queryKey: fileExplorerKeys.content(path),\n queryFn: () => fetchFileContent(path),\n staleTime: CONTENT_STALE_TIME,\n });\n }\n }, [queryClient]);\n\n // Set view mode\n const setViewMode = useCallback((mode: ExplorerState['viewMode']) => {\n setViewModeState(mode);\n }, []);\n\n // Set sort order\n const setSortOrder = useCallback((order: ExplorerState['sortOrder']) => {\n setSortOrderState(order);\n }, []);\n\n // Toggle hidden files\n const toggleShowHidden = useCallback(() => {\n setShowHiddenFiles((prev) => !prev);\n }, []);\n\n // Set filter\n const setFilter = useCallback((value: string) => {\n setFilterState(value);\n }, []);\n\n // Load file content\n const loadFileContent = useCallback(async (path: string) => {\n try {\n const content = await queryClient.fetchQuery({\n queryKey: fileExplorerKeys.content(path),\n queryFn: () => fetchFileContent(path),\n staleTime: CONTENT_STALE_TIME,\n });\n return content;\n } catch (error) {\n console.error(`[useFileExplorer] Failed to load file content: ${path}`, error);\n throw error;\n }\n }, [queryClient]);\n\n // Search files\n const searchFilesHandler = useCallback(async (query: string) => {\n if (!query.trim()) {\n setSearchResults(undefined);\n return undefined;\n }\n try {\n const results = await queryClient.fetchQuery({\n queryKey: fileExplorerKeys.search(query),\n queryFn: () => searchFiles({ rootPath, query, maxResults: 100 }),\n staleTime: 60000, // 1 minute\n });\n setSearchResults(results);\n return results;\n } catch (error) {\n console.error('[useFileExplorer] Search failed:', error);\n throw error;\n }\n }, [queryClient, rootPath]);\n\n const isSearching = queryClient.isFetching({ queryKey: fileExplorerKeys.all }) > 0;\n\n // Clear file cache\n const clearFileCache = useCallback((path?: string) => {\n if (path) {\n queryClient.removeQueries({ queryKey: fileExplorerKeys.content(path) });\n } else {\n queryClient.removeQueries({ queryKey: fileExplorerKeys.contents() });\n }\n }, [queryClient]);\n\n // Refetch\n const refetch = async () => {\n await treeQuery.refetch();\n };\n\n // Build explorer state object\n const state: ExplorerState = {\n currentPath: rootPath,\n selectedFile,\n expandedPaths,\n fileTree: rootNodes,\n viewMode,\n sortOrder,\n showHiddenFiles,\n filter,\n isLoading: treeQuery.isLoading,\n error: treeQuery.error?.message ?? null,\n fileContents: {},\n recentFiles: [],\n maxRecentFiles: 10,\n directoriesFirst: true,\n };\n\n return {\n state,\n rootNodes,\n isLoading: treeQuery.isLoading,\n isFetching: treeQuery.isFetching,\n error: treeQuery.error,\n refetch,\n setSelectedFile,\n toggleExpanded,\n expandDirectory,\n collapseDirectory,\n expandAll,\n collapseAll,\n setViewMode,\n setSortOrder,\n toggleShowHidden,\n setFilter,\n loadFileContent,\n rootDirectories,\n isLoadingRoots: rootsQuery.isLoading,\n searchFiles: searchFilesHandler,\n searchResults,\n isSearching,\n clearFileCache,\n };\n}\n\n/**\n * Hook for file content with caching\n */\nexport function useFileContent(filePath: string | null, options: {\n enabled?: boolean;\n staleTime?: number;\n} = {}) {\n const { enabled = true, staleTime = CONTENT_STALE_TIME } = options;\n\n const query = useQuery({\n queryKey: fileExplorerKeys.content(filePath ?? ''),\n queryFn: () => fetchFileContent(filePath ?? ''),\n staleTime,\n enabled: enabled && !!filePath,\n retry: 1,\n });\n\n return {\n content: query.data,\n isLoading: query.isLoading,\n error: query.error,\n refetch: () => query.refetch(),\n };\n}\n\n/**\n * WebSocket hook for real-time file updates\n *\n * @example\n * ```tsx\n * const { isConnected } = useFileExplorerWebSocket({\n * onFileChanged: (path) => {\n * console.log('File changed:', path);\n * refetch();\n * }\n * });\n * ```\n */\nexport interface UseFileExplorerWebSocketOptions {\n /** Enable WebSocket connection */\n enabled?: boolean;\n /** Callback when file changes */\n onFileChanged?: (path: string) => void;\n /** Callback when directory changes */\n onDirectoryChanged?: (path: string) => void;\n}\n\nexport interface UseFileExplorerWebSocketReturn {\n /** WebSocket connection status */\n isConnected: boolean;\n}\n\nexport function useFileExplorerWebSocket(\n options: UseFileExplorerWebSocketOptions = {}\n): UseFileExplorerWebSocketReturn {\n const { enabled = true, onFileChanged, onDirectoryChanged } = options;\n const wsRef = useRef<WebSocket | null>(null);\n const [isConnected, setIsConnected] = useState(false);\n\n useEffect(() => {\n if (!enabled) return;\n\n // Construct WebSocket URL\n const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';\n const wsUrl = `${protocol}//${window.location.host}/ws`;\n\n try {\n const ws = new WebSocket(wsUrl);\n wsRef.current = ws;\n\n ws.onopen = () => {\n console.log('[FileExplorerWS] Connected');\n setIsConnected(true);\n };\n\n ws.onmessage = (event) => {\n try {\n const data = JSON.parse(event.data);\n\n // Handle file system change events\n if (data.type === 'FILE_CHANGED') {\n const { path } = data.payload || {};\n if (path) {\n onFileChanged?.(path);\n }\n } else if (data.type === 'DIRECTORY_CHANGED') {\n const { path } = data.payload || {};\n if (path) {\n onDirectoryChanged?.(path);\n }\n }\n } catch (error) {\n console.error('[FileExplorerWS] Failed to parse message:', error);\n }\n };\n\n ws.onclose = () => {\n console.log('[FileExplorerWS] Disconnected');\n setIsConnected(false);\n wsRef.current = null;\n };\n\n ws.onerror = (error) => {\n console.error('[FileExplorerWS] Error:', error);\n setIsConnected(false);\n };\n } catch (error) {\n console.error('[FileExplorerWS] Failed to connect:', error);\n }\n\n return () => {\n if (wsRef.current) {\n wsRef.current.close();\n wsRef.current = null;\n }\n };\n }, [enabled, onFileChanged, onDirectoryChanged]);\n\n return { isConnected };\n}\n\nexport default useFileExplorer;\n"],"names":["getFileIcon","fileName","ext","_a","codeExtensions","configExtensions","FileCode","File","formatFileSize","bytes","units","size","unitIndex","TreeNode","node","level","expandedPaths","selectedPath","maxDepth","showIcons","showSizes","onNodeClick","onNodeDoubleClick","onToggle","isDirectory","isExpanded","isSelected","hasChildren","shouldShowChildren","isAtMaxDepth","Icon","FolderOpen","Folder","handleClick","e","handleDoubleClick","handleKeyDown","jsxs","cn","jsx","ChevronRight","child","TreeView","nodes","depth","className","getLanguageDisplayName","language","getFileExtension","path","parts","isBinaryFile","binaryExtensions","truncateContent","content","maxLines","lines","FilePreview","fileContent","isLoading","error","maxSize","showLineNumbers","formatMessage","useIntl","copied","setCopied","React.useState","contentRef","React.useRef","handleCopy","err","Loader2","AlertCircle","isTooLarge","extension","truncatedContent","Button","Check","Copy","_","i","fileExplorerKeys","rootPath","query","TREE_STALE_TIME","CONTENT_STALE_TIME","useFileExplorer","options","excludePatterns","staleTime","enabled","queryClient","useQueryClient","setExpandedPaths","useState","selectedFile","setSelectedFileState","viewMode","setViewModeState","sortOrder","setSortOrderState","showHiddenFiles","setShowHiddenFiles","filter","setFilterState","searchResults","setSearchResults","treeQuery","useQuery","fetchFileTree","attemptIndex","rootsQuery","fetchRootDirectories","rootNodes","rootDirectories","toggleExpanded","useCallback","prev","next","expandDirectory","collapseDirectory","expandAll","allPaths","collectPaths","collapseAll","setSelectedFile","fetchFileContent","setViewMode","mode","setSortOrder","order","toggleShowHidden","setFilter","value","loadFileContent","searchFilesHandler","results","searchFiles","isSearching","clearFileCache","refetch","_b","useFileContent","filePath"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{o as t,
|
|
2
|
-
//# sourceMappingURL=useLocale-
|
|
1
|
+
import{o as t,fI as n,r as c,fJ as l,bV as r}from"./index-BUol9HDD.js";function f(){const e=t(n),a=t(o=>o.setLocale),s=c.useCallback(o=>{a(o)},[a]);return{locale:e,setLocale:s,availableLocales:l}}function L(){return c.useMemo(()=>(e,a)=>{const s=typeof e=="string"?e:e.id;return r(s,a)},[])}export{L as a,f as u};
|
|
2
|
+
//# sourceMappingURL=useLocale-D2rj4rea.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useLocale-
|
|
1
|
+
{"version":3,"file":"useLocale-D2rj4rea.js","sources":["../../src/hooks/useLocale.ts"],"sourcesContent":["// ========================================\r\n// useLocale Hook\r\n// ========================================\r\n// Convenient hook for locale management\r\n\r\nimport { useCallback, useMemo } from 'react';\r\nimport { useAppStore, selectLocale } from '../stores/appStore';\r\nimport type { Locale } from '../types/store';\r\nimport { availableLocales, formatMessage } from '../lib/i18n';\r\n\r\nexport interface UseLocaleReturn {\r\n /** Current locale ('en' or 'zh') */\r\n locale: Locale;\r\n /** Set locale preference */\r\n setLocale: (locale: Locale) => void;\r\n /** Available locales with display names */\r\n availableLocales: Record<Locale, string>;\r\n}\r\n\r\n/**\r\n * Hook for managing locale state\r\n * @returns Locale state and actions\r\n *\r\n * @example\r\n * ```tsx\r\n * const { locale, setLocale, availableLocales } = useLocale();\r\n *\r\n * return (\r\n * <select value={locale} onChange={(e) => setLocale(e.target.value as Locale)}>\r\n * {Object.entries(availableLocales).map(([key, label]) => (\r\n * <option key={key} value={key}>{label}</option>\r\n * ))}\r\n * </select>\r\n * );\r\n * ```\r\n */\r\nexport function useLocale(): UseLocaleReturn {\r\n const locale = useAppStore(selectLocale);\r\n const setLocaleAction = useAppStore((state) => state.setLocale);\r\n\r\n const setLocale = useCallback(\r\n (newLocale: Locale) => {\r\n setLocaleAction(newLocale);\r\n },\r\n [setLocaleAction]\r\n );\r\n\r\n return {\r\n locale,\r\n setLocale,\r\n availableLocales,\r\n };\r\n}\r\n\r\n/**\r\n * Hook to format i18n messages with the current locale\r\n * @returns A formatMessage function for translating message IDs\r\n *\r\n * Supports both string and react-intl descriptor formats:\r\n * - formatMessage('home.title')\r\n * - formatMessage({ id: 'home.title' })\r\n *\r\n * @example\r\n * ```tsx\r\n * const formatMessage = useFormatMessage();\r\n * return <h1>{formatMessage('home.title')}</h1>;\r\n * ```\r\n */\r\nexport function useFormatMessage(): (\r\n idOrDescriptor: string | { id: string; defaultMessage?: string },\r\n values?: Record<string, string | number | boolean | Date | null | undefined>\r\n) => string {\r\n // Use useMemo to avoid recreating the function on each render\r\n return useMemo(() => {\r\n return (idOrDescriptor: string | { id: string; defaultMessage?: string }, values?: Record<string, string | number | boolean | Date | null | undefined>) => {\r\n const id = typeof idOrDescriptor === 'string' ? idOrDescriptor : idOrDescriptor.id;\r\n return formatMessage(id, values);\r\n };\r\n }, []);\r\n}\r\n"],"names":["useLocale","locale","useAppStore","selectLocale","setLocaleAction","state","setLocale","useCallback","newLocale","availableLocales","useFormatMessage","useMemo","idOrDescriptor","values","id","formatMessage"],"mappings":"uEAoCO,SAASA,GAA6B,CAC3C,MAAMC,EAASC,EAAYC,CAAY,EACjCC,EAAkBF,EAAaG,GAAUA,EAAM,SAAS,EAExDC,EAAYC,EAAAA,YACfC,GAAsB,CACrBJ,EAAgBI,CAAS,CAC3B,EACA,CAACJ,CAAe,CAAA,EAGlB,MAAO,CACL,OAAAH,EACA,UAAAK,EACA,iBAAAG,CAAA,CAEJ,CAgBO,SAASC,GAGJ,CAEV,OAAOC,EAAAA,QAAQ,IACN,CAACC,EAAkEC,IAAiF,CACzJ,MAAMC,EAAK,OAAOF,GAAmB,SAAWA,EAAiBA,EAAe,GAChF,OAAOG,EAAcD,EAAID,CAAM,CACjC,EACC,CAAA,CAAE,CACP"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-
|
|
2
|
-
import{aF as h,a9 as q,aa as v,aC as k,ab as D,al as E,aH as L,
|
|
3
|
-
//# sourceMappingURL=useSkills-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/index-BUol9HDD.js","assets/index-BoqylFO4.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{aF as h,a9 as q,aa as v,aC as k,ab as D,al as E,aH as L,bV as f,bW as I,bX as P,bY as Q,bZ as M}from"./index-BUol9HDD.js";import{s as x}from"./errorSanitizer-IY9pf5g4.js";const F={all:["skills"]},j=300*1e3;function V(r={}){var C;const{filter:e,staleTime:d=j,enabled:u=!0,cliType:c="claude"}=r,g=h(),l=q(v),n=c==="codex"?k.codexSkillsList(l):k.skillsList(l),i=D({queryKey:n,queryFn:()=>M(l,c),staleTime:d,enabled:u,retry:2}),o=((C=i.data)==null?void 0:C.skills)??[],a=o.filter(s=>s.location==="project"),y=o.filter(s=>s.location==="user"),b=(()=>{let s=o;if(e!=null&&e.location&&(s=s.filter(t=>t.location===e.location)),e!=null&&e.search){const t=e.search.toLowerCase();s=s.filter(m=>m.name.toLowerCase().includes(t)||m.description.toLowerCase().includes(t)||m.triggers.some(_=>_.toLowerCase().includes(t)))}return e!=null&&e.category&&(s=s.filter(t=>t.category===e.category)),e!=null&&e.source&&(s=s.filter(t=>t.source===e.source)),e!=null&&e.enabledOnly&&(s=s.filter(t=>t.enabled)),s})(),S={},p=new Set;for(const s of o){const t=s.category||"Uncategorized";p.add(t),S[t]||(S[t]=[]),S[t].push(s)}const w=o.filter(s=>s.enabled),T=async()=>{await i.refetch()},K=async()=>{if(l){const s=c==="codex"?k.codexSkills(l):k.skills(l);await g.invalidateQueries({queryKey:s})}};return{skills:b,enabledSkills:w,categories:Array.from(p).sort(),skillsByCategory:S,totalCount:o.length,enabledCount:w.length,projectSkills:a,userSkills:y,isLoading:i.isLoading,isFetching:i.isFetching,error:i.error,refetch:T,invalidate:K}}function A(){const r=h(),e=q(v),{addToast:d,removeToast:u,success:c,error:g}=E(),l=L({mutationFn:({skillName:n,enabled:i,location:o,cliType:a="claude"})=>i?I(n,o,e,a):P(n,o,e,a),onMutate:()=>({loadingId:d("info",f("common.loading"),void 0,{duration:0})}),onSuccess:(n,i,o)=>{const{loadingId:a}=o??{loadingId:""};a&&u(a);const y=i.enabled?"skillEnable":"skillDisable";c(f(`feedback.${y}.success`)),e?(r.invalidateQueries({queryKey:k.skills(e)}),r.invalidateQueries({queryKey:k.codexSkills(e)})):r.invalidateQueries({queryKey:["skills"]})},onError:(n,i,o)=>{const{loadingId:a}=o??{loadingId:""};a&&u(a);const y=i.enabled?"skillEnable":"skillDisable",b=x(n,y);g(f("common.error"),f(b.messageKey))}});return{toggleSkill:(n,i,o,a)=>l.mutateAsync({skillName:n,enabled:i,location:o,cliType:a}),isToggling:l.isPending,error:l.error}}function z(){const r=h(),e=L({mutationFn:async({skillName:d,location:u,projectPath:c,cliType:g})=>{const{deleteSkill:l}=await Q(async()=>{const{deleteSkill:n}=await import("./index-BUol9HDD.js").then(i=>i.ge);return{deleteSkill:n}},__vite__mapDeps([0,1]));return l(d,u,c,g)},onSuccess:()=>{r.invalidateQueries({queryKey:F.all})}});return{deleteSkill:(d,u,c,g="claude")=>e.mutateAsync({skillName:d,location:u,projectPath:c,cliType:g}),isDeleting:e.isPending,error:e.error}}function W(){const r=A(),e=z();return{toggleSkill:r.toggleSkill,isToggling:r.isToggling,deleteSkill:e.deleteSkill,isDeleting:e.isDeleting,isMutating:r.isToggling||e.isDeleting}}export{W as a,V as u};
|
|
3
|
+
//# sourceMappingURL=useSkills-OskEpomF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":["skillsKeys","STALE_TIME","useSkills","options","filter","staleTime","enabled","cliType","queryClient","useQueryClient","projectPath","useWorkflowStore","selectProjectPath","queryKey","workspaceQueryKeys","query","useQuery","fetchSkills","allSkills","_a","projectSkills","userSkills","filteredSkills","skills","s","searchLower","t","skillsByCategory","categories","skill","category","enabledSkills","refetch","invalidate","invalidateKey","useToggleSkill","addToast","removeToast","success","error","useNotifications","mutation","useMutation","skillName","location","enableSkill","disableSkill","formatMessage","_","variables","context","loadingId","operation","err","sanitized","sanitizeErrorMessage","useDeleteSkill","deleteSkill","__vitePreload","n","useSkillMutations","toggle","deleteSkillHook"],"ignoreList":[],"sources":["../../src/hooks/useSkills.ts"],"sourcesContent":["// ========================================\r\n// useSkills Hook\r\n// ========================================\r\n// TanStack Query hooks for skills management\r\n\r\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\r\nimport {\r\n fetchSkills,\r\n enableSkill,\r\n disableSkill,\r\n type Skill,\r\n} from '../lib/api';\r\nimport { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore';\r\nimport { workspaceQueryKeys } from '@/lib/queryKeys';\r\nimport { useNotifications } from './useNotifications';\r\nimport { sanitizeErrorMessage } from '@/utils/errorSanitizer';\r\nimport { formatMessage } from '@/lib/i18n';\r\n\r\n// Query key factory\r\nexport const skillsKeys = {\r\n all: ['skills'] as const,\r\n lists: () => [...skillsKeys.all, 'list'] as const,\r\n list: (filters?: SkillsFilter) => [...skillsKeys.lists(), filters] as const,\r\n};\r\n\r\n// Default stale time: 5 minutes (skills don't change frequently)\r\nconst STALE_TIME = 5 * 60 * 1000;\r\n\r\nexport interface SkillsFilter {\r\n search?: string;\r\n category?: string;\r\n source?: Skill['source'];\r\n enabledOnly?: boolean;\r\n location?: 'project' | 'user';\r\n}\r\n\r\nexport interface UseSkillsOptions {\r\n filter?: SkillsFilter;\r\n staleTime?: number;\r\n enabled?: boolean;\r\n cliType?: 'claude' | 'codex';\r\n}\r\n\r\nexport interface UseSkillsReturn {\r\n skills: Skill[];\r\n enabledSkills: Skill[];\r\n categories: string[];\r\n skillsByCategory: Record<string, Skill[]>;\r\n totalCount: number;\r\n enabledCount: number;\r\n projectSkills: Skill[];\r\n userSkills: Skill[];\r\n isLoading: boolean;\r\n isFetching: boolean;\r\n error: Error | null;\r\n refetch: () => Promise<void>;\r\n invalidate: () => Promise<void>;\r\n}\r\n\r\n/**\r\n * Hook for fetching and filtering skills\r\n */\r\nexport function useSkills(options: UseSkillsOptions = {}): UseSkillsReturn {\r\n const { filter, staleTime = STALE_TIME, enabled = true, cliType = 'claude' } = options;\r\n const queryClient = useQueryClient();\r\n const projectPath = useWorkflowStore(selectProjectPath);\r\n\r\n const queryKey = cliType === 'codex'\r\n ? workspaceQueryKeys.codexSkillsList(projectPath)\r\n : workspaceQueryKeys.skillsList(projectPath);\r\n\r\n const query = useQuery({\r\n queryKey,\r\n queryFn: () => fetchSkills(projectPath, cliType),\r\n staleTime,\r\n enabled: enabled,\r\n retry: 2,\r\n });\r\n\r\n const allSkills = query.data?.skills ?? [];\r\n\r\n // Separate by location\r\n const projectSkills = allSkills.filter(s => s.location === 'project');\r\n const userSkills = allSkills.filter(s => s.location === 'user');\r\n\r\n // Apply filters\r\n const filteredSkills = (() => {\r\n let skills = allSkills;\r\n\r\n if (filter?.location) {\r\n skills = skills.filter((s) => s.location === filter.location);\r\n }\r\n\r\n if (filter?.search) {\r\n const searchLower = filter.search.toLowerCase();\r\n skills = skills.filter(\r\n (s) =>\r\n s.name.toLowerCase().includes(searchLower) ||\r\n s.description.toLowerCase().includes(searchLower) ||\r\n s.triggers.some((t) => t.toLowerCase().includes(searchLower))\r\n );\r\n }\r\n\r\n if (filter?.category) {\r\n skills = skills.filter((s) => s.category === filter.category);\r\n }\r\n\r\n if (filter?.source) {\r\n skills = skills.filter((s) => s.source === filter.source);\r\n }\r\n\r\n if (filter?.enabledOnly) {\r\n skills = skills.filter((s) => s.enabled);\r\n }\r\n\r\n return skills;\r\n })();\r\n\r\n // Group by category\r\n const skillsByCategory: Record<string, Skill[]> = {};\r\n const categories = new Set<string>();\r\n\r\n for (const skill of allSkills) {\r\n const category = skill.category || 'Uncategorized';\r\n categories.add(category);\r\n if (!skillsByCategory[category]) {\r\n skillsByCategory[category] = [];\r\n }\r\n skillsByCategory[category].push(skill);\r\n }\r\n\r\n const enabledSkills = allSkills.filter((s) => s.enabled);\r\n\r\n const refetch = async () => {\r\n await query.refetch();\r\n };\r\n\r\n const invalidate = async () => {\r\n if (projectPath) {\r\n const invalidateKey = cliType === 'codex'\r\n ? workspaceQueryKeys.codexSkills(projectPath)\r\n : workspaceQueryKeys.skills(projectPath);\r\n await queryClient.invalidateQueries({ queryKey: invalidateKey });\r\n }\r\n };\r\n\r\n return {\r\n skills: filteredSkills,\r\n enabledSkills,\r\n categories: Array.from(categories).sort(),\r\n skillsByCategory,\r\n totalCount: allSkills.length,\r\n enabledCount: enabledSkills.length,\r\n projectSkills,\r\n userSkills,\r\n isLoading: query.isLoading,\r\n isFetching: query.isFetching,\r\n error: query.error,\r\n refetch,\r\n invalidate,\r\n };\r\n}\r\n\r\n// ========== Mutations ==========\r\n\r\nexport interface UseToggleSkillReturn {\r\n toggleSkill: (skillName: string, enabled: boolean, location: 'project' | 'user', cliType?: 'claude' | 'codex') => Promise<Skill>;\r\n isToggling: boolean;\r\n error: Error | null;\r\n}\r\n\r\nexport function useToggleSkill(): UseToggleSkillReturn {\r\n const queryClient = useQueryClient();\r\n const projectPath = useWorkflowStore(selectProjectPath);\r\n const { addToast, removeToast, success, error } = useNotifications();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ skillName, enabled, location, cliType = 'claude' }: { skillName: string; enabled: boolean; location: 'project' | 'user'; cliType?: 'claude' | 'codex' }) =>\r\n enabled\r\n ? enableSkill(skillName, location, projectPath, cliType)\r\n : disableSkill(skillName, location, projectPath, cliType),\r\n onMutate: (): { loadingId: string } => {\r\n const loadingId = addToast('info', formatMessage('common.loading'), undefined, { duration: 0 });\r\n return { loadingId };\r\n },\r\n onSuccess: (_, variables, context) => {\r\n const { loadingId } = context ?? { loadingId: '' };\r\n if (loadingId) removeToast(loadingId);\r\n\r\n const operation = variables.enabled ? 'skillEnable' : 'skillDisable';\r\n success(formatMessage(`feedback.${operation}.success`));\r\n\r\n // Invalidate both claude and codex skills queries\r\n if (projectPath) {\r\n queryClient.invalidateQueries({ queryKey: workspaceQueryKeys.skills(projectPath) });\r\n queryClient.invalidateQueries({ queryKey: workspaceQueryKeys.codexSkills(projectPath) });\r\n } else {\r\n queryClient.invalidateQueries({ queryKey: ['skills'] });\r\n }\r\n },\r\n onError: (err, variables, context) => {\r\n const { loadingId } = context ?? { loadingId: '' };\r\n if (loadingId) removeToast(loadingId);\r\n\r\n const operation = variables.enabled ? 'skillEnable' : 'skillDisable';\r\n const sanitized = sanitizeErrorMessage(err, operation);\r\n error(formatMessage('common.error'), formatMessage(sanitized.messageKey));\r\n },\r\n });\r\n\r\n return {\r\n toggleSkill: (skillName, enabled, location, cliType) => mutation.mutateAsync({ skillName, enabled, location, cliType }),\r\n isToggling: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n/**\r\n * Hook for deleting a skill\r\n */\r\nexport function useDeleteSkill() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: async ({\r\n skillName,\r\n location,\r\n projectPath,\r\n cliType,\r\n }: {\r\n skillName: string;\r\n location: 'project' | 'user';\r\n projectPath?: string;\r\n cliType: 'claude' | 'codex';\r\n }) => {\r\n const { deleteSkill } = await import('@/lib/api');\r\n return deleteSkill(skillName, location, projectPath, cliType);\r\n },\r\n onSuccess: () => {\r\n // Invalidate skills queries to refresh the list\r\n queryClient.invalidateQueries({ queryKey: skillsKeys.all });\r\n },\r\n });\r\n\r\n return {\r\n deleteSkill: (skillName: string, location: 'project' | 'user', projectPath?: string, cliType: 'claude' | 'codex' = 'claude') =>\r\n mutation.mutateAsync({ skillName, location, projectPath, cliType }),\r\n isDeleting: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n/**\r\n * Combined hook for all skill mutations\r\n */\r\nexport function useSkillMutations() {\r\n const toggle = useToggleSkill();\r\n const deleteSkillHook = useDeleteSkill();\r\n\r\n return {\r\n toggleSkill: toggle.toggleSkill,\r\n isToggling: toggle.isToggling,\r\n deleteSkill: deleteSkillHook.deleteSkill,\r\n isDeleting: deleteSkillHook.isDeleting,\r\n isMutating: toggle.isToggling || deleteSkillHook.isDeleting,\r\n };\r\n}\r\n"],"file":"assets/useSkills-cxKXMBm3.js"}
|
|
1
|
+
{"version":3,"mappings":"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","names":["skillsKeys","STALE_TIME","useSkills","options","filter","staleTime","enabled","cliType","queryClient","useQueryClient","projectPath","useWorkflowStore","selectProjectPath","queryKey","workspaceQueryKeys","query","useQuery","fetchSkills","allSkills","_a","projectSkills","userSkills","filteredSkills","skills","s","searchLower","t","skillsByCategory","categories","skill","category","enabledSkills","refetch","invalidate","invalidateKey","useToggleSkill","addToast","removeToast","success","error","useNotifications","mutation","useMutation","skillName","location","enableSkill","disableSkill","formatMessage","_","variables","context","loadingId","operation","err","sanitized","sanitizeErrorMessage","useDeleteSkill","deleteSkill","__vitePreload","n","useSkillMutations","toggle","deleteSkillHook"],"ignoreList":[],"sources":["../../src/hooks/useSkills.ts"],"sourcesContent":["// ========================================\r\n// useSkills Hook\r\n// ========================================\r\n// TanStack Query hooks for skills management\r\n\r\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\r\nimport {\r\n fetchSkills,\r\n enableSkill,\r\n disableSkill,\r\n type Skill,\r\n} from '../lib/api';\r\nimport { useWorkflowStore, selectProjectPath } from '@/stores/workflowStore';\r\nimport { workspaceQueryKeys } from '@/lib/queryKeys';\r\nimport { useNotifications } from './useNotifications';\r\nimport { sanitizeErrorMessage } from '@/utils/errorSanitizer';\r\nimport { formatMessage } from '@/lib/i18n';\r\n\r\n// Query key factory\r\nexport const skillsKeys = {\r\n all: ['skills'] as const,\r\n lists: () => [...skillsKeys.all, 'list'] as const,\r\n list: (filters?: SkillsFilter) => [...skillsKeys.lists(), filters] as const,\r\n};\r\n\r\n// Default stale time: 5 minutes (skills don't change frequently)\r\nconst STALE_TIME = 5 * 60 * 1000;\r\n\r\nexport interface SkillsFilter {\r\n search?: string;\r\n category?: string;\r\n source?: Skill['source'];\r\n enabledOnly?: boolean;\r\n location?: 'project' | 'user';\r\n}\r\n\r\nexport interface UseSkillsOptions {\r\n filter?: SkillsFilter;\r\n staleTime?: number;\r\n enabled?: boolean;\r\n cliType?: 'claude' | 'codex';\r\n}\r\n\r\nexport interface UseSkillsReturn {\r\n skills: Skill[];\r\n enabledSkills: Skill[];\r\n categories: string[];\r\n skillsByCategory: Record<string, Skill[]>;\r\n totalCount: number;\r\n enabledCount: number;\r\n projectSkills: Skill[];\r\n userSkills: Skill[];\r\n isLoading: boolean;\r\n isFetching: boolean;\r\n error: Error | null;\r\n refetch: () => Promise<void>;\r\n invalidate: () => Promise<void>;\r\n}\r\n\r\n/**\r\n * Hook for fetching and filtering skills\r\n */\r\nexport function useSkills(options: UseSkillsOptions = {}): UseSkillsReturn {\r\n const { filter, staleTime = STALE_TIME, enabled = true, cliType = 'claude' } = options;\r\n const queryClient = useQueryClient();\r\n const projectPath = useWorkflowStore(selectProjectPath);\r\n\r\n const queryKey = cliType === 'codex'\r\n ? workspaceQueryKeys.codexSkillsList(projectPath)\r\n : workspaceQueryKeys.skillsList(projectPath);\r\n\r\n const query = useQuery({\r\n queryKey,\r\n queryFn: () => fetchSkills(projectPath, cliType),\r\n staleTime,\r\n enabled: enabled,\r\n retry: 2,\r\n });\r\n\r\n const allSkills = query.data?.skills ?? [];\r\n\r\n // Separate by location\r\n const projectSkills = allSkills.filter(s => s.location === 'project');\r\n const userSkills = allSkills.filter(s => s.location === 'user');\r\n\r\n // Apply filters\r\n const filteredSkills = (() => {\r\n let skills = allSkills;\r\n\r\n if (filter?.location) {\r\n skills = skills.filter((s) => s.location === filter.location);\r\n }\r\n\r\n if (filter?.search) {\r\n const searchLower = filter.search.toLowerCase();\r\n skills = skills.filter(\r\n (s) =>\r\n s.name.toLowerCase().includes(searchLower) ||\r\n s.description.toLowerCase().includes(searchLower) ||\r\n s.triggers.some((t) => t.toLowerCase().includes(searchLower))\r\n );\r\n }\r\n\r\n if (filter?.category) {\r\n skills = skills.filter((s) => s.category === filter.category);\r\n }\r\n\r\n if (filter?.source) {\r\n skills = skills.filter((s) => s.source === filter.source);\r\n }\r\n\r\n if (filter?.enabledOnly) {\r\n skills = skills.filter((s) => s.enabled);\r\n }\r\n\r\n return skills;\r\n })();\r\n\r\n // Group by category\r\n const skillsByCategory: Record<string, Skill[]> = {};\r\n const categories = new Set<string>();\r\n\r\n for (const skill of allSkills) {\r\n const category = skill.category || 'Uncategorized';\r\n categories.add(category);\r\n if (!skillsByCategory[category]) {\r\n skillsByCategory[category] = [];\r\n }\r\n skillsByCategory[category].push(skill);\r\n }\r\n\r\n const enabledSkills = allSkills.filter((s) => s.enabled);\r\n\r\n const refetch = async () => {\r\n await query.refetch();\r\n };\r\n\r\n const invalidate = async () => {\r\n if (projectPath) {\r\n const invalidateKey = cliType === 'codex'\r\n ? workspaceQueryKeys.codexSkills(projectPath)\r\n : workspaceQueryKeys.skills(projectPath);\r\n await queryClient.invalidateQueries({ queryKey: invalidateKey });\r\n }\r\n };\r\n\r\n return {\r\n skills: filteredSkills,\r\n enabledSkills,\r\n categories: Array.from(categories).sort(),\r\n skillsByCategory,\r\n totalCount: allSkills.length,\r\n enabledCount: enabledSkills.length,\r\n projectSkills,\r\n userSkills,\r\n isLoading: query.isLoading,\r\n isFetching: query.isFetching,\r\n error: query.error,\r\n refetch,\r\n invalidate,\r\n };\r\n}\r\n\r\n// ========== Mutations ==========\r\n\r\nexport interface UseToggleSkillReturn {\r\n toggleSkill: (skillName: string, enabled: boolean, location: 'project' | 'user', cliType?: 'claude' | 'codex') => Promise<Skill>;\r\n isToggling: boolean;\r\n error: Error | null;\r\n}\r\n\r\nexport function useToggleSkill(): UseToggleSkillReturn {\r\n const queryClient = useQueryClient();\r\n const projectPath = useWorkflowStore(selectProjectPath);\r\n const { addToast, removeToast, success, error } = useNotifications();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ skillName, enabled, location, cliType = 'claude' }: { skillName: string; enabled: boolean; location: 'project' | 'user'; cliType?: 'claude' | 'codex' }) =>\r\n enabled\r\n ? enableSkill(skillName, location, projectPath, cliType)\r\n : disableSkill(skillName, location, projectPath, cliType),\r\n onMutate: (): { loadingId: string } => {\r\n const loadingId = addToast('info', formatMessage('common.loading'), undefined, { duration: 0 });\r\n return { loadingId };\r\n },\r\n onSuccess: (_, variables, context) => {\r\n const { loadingId } = context ?? { loadingId: '' };\r\n if (loadingId) removeToast(loadingId);\r\n\r\n const operation = variables.enabled ? 'skillEnable' : 'skillDisable';\r\n success(formatMessage(`feedback.${operation}.success`));\r\n\r\n // Invalidate both claude and codex skills queries\r\n if (projectPath) {\r\n queryClient.invalidateQueries({ queryKey: workspaceQueryKeys.skills(projectPath) });\r\n queryClient.invalidateQueries({ queryKey: workspaceQueryKeys.codexSkills(projectPath) });\r\n } else {\r\n queryClient.invalidateQueries({ queryKey: ['skills'] });\r\n }\r\n },\r\n onError: (err, variables, context) => {\r\n const { loadingId } = context ?? { loadingId: '' };\r\n if (loadingId) removeToast(loadingId);\r\n\r\n const operation = variables.enabled ? 'skillEnable' : 'skillDisable';\r\n const sanitized = sanitizeErrorMessage(err, operation);\r\n error(formatMessage('common.error'), formatMessage(sanitized.messageKey));\r\n },\r\n });\r\n\r\n return {\r\n toggleSkill: (skillName, enabled, location, cliType) => mutation.mutateAsync({ skillName, enabled, location, cliType }),\r\n isToggling: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n/**\r\n * Hook for deleting a skill\r\n */\r\nexport function useDeleteSkill() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: async ({\r\n skillName,\r\n location,\r\n projectPath,\r\n cliType,\r\n }: {\r\n skillName: string;\r\n location: 'project' | 'user';\r\n projectPath?: string;\r\n cliType: 'claude' | 'codex';\r\n }) => {\r\n const { deleteSkill } = await import('@/lib/api');\r\n return deleteSkill(skillName, location, projectPath, cliType);\r\n },\r\n onSuccess: () => {\r\n // Invalidate skills queries to refresh the list\r\n queryClient.invalidateQueries({ queryKey: skillsKeys.all });\r\n },\r\n });\r\n\r\n return {\r\n deleteSkill: (skillName: string, location: 'project' | 'user', projectPath?: string, cliType: 'claude' | 'codex' = 'claude') =>\r\n mutation.mutateAsync({ skillName, location, projectPath, cliType }),\r\n isDeleting: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n/**\r\n * Combined hook for all skill mutations\r\n */\r\nexport function useSkillMutations() {\r\n const toggle = useToggleSkill();\r\n const deleteSkillHook = useDeleteSkill();\r\n\r\n return {\r\n toggleSkill: toggle.toggleSkill,\r\n isToggling: toggle.isToggling,\r\n deleteSkill: deleteSkillHook.deleteSkill,\r\n isDeleting: deleteSkillHook.isDeleting,\r\n isMutating: toggle.isToggling || deleteSkillHook.isDeleting,\r\n };\r\n}\r\n"],"file":"assets/useSkills-OskEpomF.js"}
|
package/ccw/frontend/dist/assets/{useSystemSettings-B-xUT_z-.js → useSystemSettings-BjMgsNSF.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{ab as o,aF as c,aH as u,
|
|
2
|
-
//# sourceMappingURL=useSystemSettings-
|
|
1
|
+
import{ab as o,aF as c,aH as u,fW as g,fX as d,fY as y,fZ as m,f_ as f,f$ as S,g0 as h,g1 as q,g2 as p,g3 as C,g4 as P,g5 as L,g6 as w,g7 as K,g8 as x,g9 as F,ga as T,gb as I}from"./index-BUol9HDD.js";const r={all:["systemSettings"],chineseResponse:()=>[...r.all,"chineseResponse"],windowsPlatform:()=>[...r.all,"windowsPlatform"],codexCliEnhancement:()=>[...r.all,"codexCliEnhancement"],aggregatedStatus:()=>[...r.all,"aggregatedStatus"],cliToolStatus:()=>[...r.all,"cliToolStatus"],ccwInstallations:()=>[...r.all,"ccwInstallations"],exportSettings:()=>[...r.all,"exportSettings"]},l=60*1e3;function A(){const e=o({queryKey:r.chineseResponse(),queryFn:C,staleTime:l,retry:1});return{data:e.data,isLoading:e.isLoading,error:e.error,refetch:()=>{e.refetch()}}}function Q(){const e=c(),t=u({mutationFn:({enabled:n,target:s})=>g(n,s),onSuccess:()=>{e.invalidateQueries({queryKey:r.chineseResponse()})}});return{toggle:(n,s)=>t.mutateAsync({enabled:n,target:s}),isPending:t.isPending,error:t.error}}function R(){const e=o({queryKey:r.windowsPlatform(),queryFn:P,staleTime:l,retry:1});return{data:e.data,isLoading:e.isLoading,error:e.error,refetch:()=>{e.refetch()}}}function v(){const e=c(),t=u({mutationFn:n=>d(n),onSuccess:()=>{e.invalidateQueries({queryKey:r.windowsPlatform()})}});return{toggle:t.mutateAsync,isPending:t.isPending,error:t.error}}function b(){const e=o({queryKey:r.codexCliEnhancement(),queryFn:L,staleTime:l,retry:1});return{data:e.data,isLoading:e.isLoading,error:e.error,refetch:()=>{e.refetch()}}}function W(){const e=c(),t=u({mutationFn:n=>y(n),onSuccess:()=>{e.invalidateQueries({queryKey:r.codexCliEnhancement()})}});return{toggle:t.mutateAsync,isPending:t.isPending,error:t.error}}function j(){const e=c(),t=u({mutationFn:()=>m(),onSuccess:()=>{e.invalidateQueries({queryKey:r.codexCliEnhancement()})}});return{refresh:t.mutateAsync,isPending:t.isPending,error:t.error}}function k(){var t;const e=o({queryKey:r.aggregatedStatus(),queryFn:w,staleTime:3e5,retry:1});return{data:(t=e.data)==null?void 0:t.ccwInstall,isLoading:e.isLoading,error:e.error,refetch:()=>{e.refetch()}}}function H(){const e=o({queryKey:r.cliToolStatus(),queryFn:K,staleTime:12e4,retry:1});return{data:e.data,isLoading:e.isLoading,error:e.error,refetch:()=>{e.refetch()}}}function M(){var t;const e=o({queryKey:r.ccwInstallations(),queryFn:x,staleTime:3e5,retry:1});return{installations:((t=e.data)==null?void 0:t.installations)??[],isLoading:e.isLoading,error:e.error,refetch:()=>{e.refetch()}}}function _(){const e=c(),t=u({mutationFn:n=>h(n),onSuccess:()=>{e.invalidateQueries({queryKey:r.ccwInstallations()}),e.invalidateQueries({queryKey:r.aggregatedStatus()})}});return{upgrade:t.mutateAsync,isPending:t.isPending,error:t.error}}function U(){const e=u({mutationFn:f});return{exportSettings:e.mutateAsync,isPending:e.isPending,error:e.error}}function X(){const e=c(),t=u({mutationFn:({data:n,options:s})=>S(n,s),onSuccess:()=>{e.invalidateQueries({queryKey:r.all})}});return{importSettings:(n,s)=>t.mutateAsync({data:n,options:s}),isPending:t.isPending,error:t.error}}const i={all:["specsSettings"],systemSettings:()=>[...i.all,"systemSettings"],specStats:e=>[...i.all,"specStats",e],specsList:e=>[...i.all,"specsList",e]};function Y(){const e=o({queryKey:i.systemSettings(),queryFn:F,staleTime:l,retry:1});return{data:e.data,isLoading:e.isLoading,error:e.error,refetch:()=>{e.refetch()}}}function Z(){const e=c(),t=u({mutationFn:({hookIds:n,scope:s})=>p(n,s),onSuccess:()=>{e.invalidateQueries({queryKey:i.systemSettings()})}});return{installHooks:(n,s)=>t.mutateAsync({hookIds:n,scope:s}),isPending:t.isPending,error:t.error,data:t.data}}function $(e={}){const{projectPath:t,enabled:n=!0,staleTime:s=l}=e,a=o({queryKey:i.specStats(t),queryFn:()=>T(t),staleTime:s,enabled:n,retry:1});return{data:a.data,isLoading:a.isLoading,error:a.error,refetch:()=>{a.refetch()}}}function z(e={}){const{projectPath:t,enabled:n=!0,staleTime:s=l}=e,a=o({queryKey:i.specsList(t),queryFn:()=>I(t),staleTime:s,enabled:n,retry:1});return{data:a.data,isLoading:a.isLoading,error:a.error,refetch:()=>{a.refetch()}}}function B(e={}){const{projectPath:t}=e,n=c(),s=u({mutationFn:()=>q(t),onSuccess:()=>{n.invalidateQueries({queryKey:i.specStats(t)}),n.invalidateQueries({queryKey:i.specsList(t)})}});return{mutate:s.mutate,mutateAsync:s.mutateAsync,isPending:s.isPending,error:s.error,data:s.data}}export{Q as a,R as b,v as c,b as d,W as e,j as f,U as g,X as h,M as i,_ as j,k,H as l,Z as m,Y as n,z as o,$ as p,B as q,A as u};
|
|
2
|
+
//# sourceMappingURL=useSystemSettings-BjMgsNSF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSystemSettings-B-xUT_z-.js","sources":["../../src/hooks/useSystemSettings.ts"],"sourcesContent":["// ========================================\r\n// useSystemSettings Hook\r\n// ========================================\r\n// TanStack Query hooks for system settings (language, install status, tool status)\r\n\r\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\r\nimport {\r\n fetchChineseResponseStatus,\r\n toggleChineseResponse,\r\n fetchWindowsPlatformStatus,\r\n toggleWindowsPlatform,\r\n fetchCodexCliEnhancementStatus,\r\n toggleCodexCliEnhancement,\r\n refreshCodexCliEnhancement,\r\n fetchAggregatedStatus,\r\n fetchCliToolStatus,\r\n fetchCcwInstallations,\r\n upgradeCcwInstallation,\r\n exportSettings,\r\n importSettings,\r\n type ChineseResponseStatus,\r\n type WindowsPlatformStatus,\r\n type CodexCliEnhancementStatus,\r\n type CcwInstallStatus,\r\n type CcwInstallationManifest,\r\n type ExportedSettings,\r\n type ImportOptions,\r\n} from '../lib/api';\r\n\r\n// Query key factory\r\nexport const systemSettingsKeys = {\r\n all: ['systemSettings'] as const,\r\n chineseResponse: () => [...systemSettingsKeys.all, 'chineseResponse'] as const,\r\n windowsPlatform: () => [...systemSettingsKeys.all, 'windowsPlatform'] as const,\r\n codexCliEnhancement: () => [...systemSettingsKeys.all, 'codexCliEnhancement'] as const,\r\n aggregatedStatus: () => [...systemSettingsKeys.all, 'aggregatedStatus'] as const,\r\n cliToolStatus: () => [...systemSettingsKeys.all, 'cliToolStatus'] as const,\r\n ccwInstallations: () => [...systemSettingsKeys.all, 'ccwInstallations'] as const,\r\n exportSettings: () => [...systemSettingsKeys.all, 'exportSettings'] as const,\r\n};\r\n\r\nconst STALE_TIME = 60 * 1000; // 1 minute\r\n\r\n// ========================================\r\n// Chinese Response Hooks\r\n// ========================================\r\n\r\nexport interface UseChineseResponseStatusReturn {\r\n data: ChineseResponseStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useChineseResponseStatus(): UseChineseResponseStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.chineseResponse(),\r\n queryFn: fetchChineseResponseStatus,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useToggleChineseResponse() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ enabled, target }: { enabled: boolean; target: 'claude' | 'codex' }) =>\r\n toggleChineseResponse(enabled, target),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.chineseResponse() });\r\n },\r\n });\r\n\r\n return {\r\n toggle: (enabled: boolean, target: 'claude' | 'codex') =>\r\n mutation.mutateAsync({ enabled, target }),\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Windows Platform Hooks\r\n// ========================================\r\n\r\nexport interface UseWindowsPlatformStatusReturn {\r\n data: WindowsPlatformStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useWindowsPlatformStatus(): UseWindowsPlatformStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.windowsPlatform(),\r\n queryFn: fetchWindowsPlatformStatus,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useToggleWindowsPlatform() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (enabled: boolean) => toggleWindowsPlatform(enabled),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.windowsPlatform() });\r\n },\r\n });\r\n\r\n return {\r\n toggle: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Codex CLI Enhancement Hooks\r\n// ========================================\r\n\r\nexport interface UseCodexCliEnhancementStatusReturn {\r\n data: CodexCliEnhancementStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCodexCliEnhancementStatus(): UseCodexCliEnhancementStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.codexCliEnhancement(),\r\n queryFn: fetchCodexCliEnhancementStatus,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useToggleCodexCliEnhancement() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (enabled: boolean) => toggleCodexCliEnhancement(enabled),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.codexCliEnhancement() });\r\n },\r\n });\r\n\r\n return {\r\n toggle: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\nexport function useRefreshCodexCliEnhancement() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: () => refreshCodexCliEnhancement(),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.codexCliEnhancement() });\r\n },\r\n });\r\n\r\n return {\r\n refresh: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Aggregated Status / CCW Install Hooks\r\n// ========================================\r\n\r\nexport interface UseCcwInstallStatusReturn {\r\n data: CcwInstallStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCcwInstallStatus(): UseCcwInstallStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.aggregatedStatus(),\r\n queryFn: fetchAggregatedStatus,\r\n staleTime: 5 * 60 * 1000, // 5 minutes\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data?.ccwInstall,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// CLI Tool Status Hooks\r\n// ========================================\r\n\r\nexport interface UseCliToolStatusReturn {\r\n data: Record<string, { available: boolean; path?: string; version?: string }> | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCliToolStatus(): UseCliToolStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.cliToolStatus(),\r\n queryFn: fetchCliToolStatus,\r\n staleTime: 2 * 60 * 1000, // 2 minutes\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// CCW Installations Hooks\r\n// ========================================\r\n\r\nexport interface UseCcwInstallationsReturn {\r\n installations: CcwInstallationManifest[];\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCcwInstallations(): UseCcwInstallationsReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.ccwInstallations(),\r\n queryFn: fetchCcwInstallations,\r\n staleTime: 5 * 60 * 1000, // 5 minutes\r\n retry: 1,\r\n });\r\n\r\n return {\r\n installations: query.data?.installations ?? [],\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useUpgradeCcwInstallation() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (path?: string) => upgradeCcwInstallation(path),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.ccwInstallations() });\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.aggregatedStatus() });\r\n },\r\n });\r\n\r\n return {\r\n upgrade: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Settings Export/Import Hooks\r\n// ========================================\r\n\r\nexport function useExportSettings() {\r\n const mutation = useMutation({\r\n mutationFn: exportSettings,\r\n });\r\n\r\n return {\r\n exportSettings: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\nexport function useImportSettings() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ data, options }: { data: ExportedSettings; options?: ImportOptions }) =>\r\n importSettings(data, options),\r\n onSuccess: () => {\r\n // Invalidate all system settings queries to refresh the UI\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.all });\r\n },\r\n });\r\n\r\n return {\r\n importSettings: (data: ExportedSettings, options?: ImportOptions) =>\r\n mutation.mutateAsync({ data, options }),\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Specs Settings Hooks\r\n// ========================================\r\n\r\nimport {\r\n getSystemSettings,\r\n updateSystemSettings,\r\n installRecommendedHooks,\r\n getSpecStats,\r\n getSpecsList,\r\n rebuildSpecIndex,\r\n updateSpecFrontmatter,\r\n type SystemSettings,\r\n type UpdateSystemSettingsInput,\r\n type SpecStats,\r\n type SpecsListResponse,\r\n} from '../lib/api';\r\n\r\n// Query keys for specs settings\r\nexport const specsSettingsKeys = {\r\n all: ['specsSettings'] as const,\r\n systemSettings: () => [...specsSettingsKeys.all, 'systemSettings'] as const,\r\n specStats: (projectPath?: string) => [...specsSettingsKeys.all, 'specStats', projectPath] as const,\r\n specsList: (projectPath?: string) => [...specsSettingsKeys.all, 'specsList', projectPath] as const,\r\n};\r\n\r\n// ========================================\r\n// System Settings Query Hook\r\n// ========================================\r\n\r\nexport interface UseSystemSettingsReturn {\r\n data: SystemSettings | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\n/**\r\n * Hook to fetch system settings (injection control, personal spec defaults, recommended hooks)\r\n */\r\nexport function useSystemSettings(): UseSystemSettingsReturn {\r\n const query = useQuery({\r\n queryKey: specsSettingsKeys.systemSettings(),\r\n queryFn: getSystemSettings,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// Update System Settings Mutation Hook\r\n// ========================================\r\n\r\nexport function useUpdateSystemSettings() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (data: UpdateSystemSettingsInput) => updateSystemSettings(data),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.systemSettings() });\r\n },\r\n });\r\n\r\n return {\r\n updateSettings: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Install Recommended Hooks Mutation Hook\r\n// ========================================\r\n\r\nexport function useInstallRecommendedHooks() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ hookIds, scope }: { hookIds: string[]; scope?: 'global' | 'project' }) =>\r\n installRecommendedHooks(hookIds, scope),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.systemSettings() });\r\n },\r\n });\r\n\r\n return {\r\n installHooks: (hookIds: string[], scope?: 'global' | 'project') =>\r\n mutation.mutateAsync({ hookIds, scope }),\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n data: mutation.data,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Spec Stats Query Hook\r\n// ========================================\r\n\r\nexport interface UseSpecStatsOptions {\r\n projectPath?: string;\r\n enabled?: boolean;\r\n staleTime?: number;\r\n}\r\n\r\nexport interface UseSpecStatsReturn {\r\n data: SpecStats | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\n/**\r\n * Hook to fetch spec statistics (dimensions count, injection length info)\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useSpecStats(options: UseSpecStatsOptions = {}): UseSpecStatsReturn {\r\n const { projectPath, enabled = true, staleTime = STALE_TIME } = options;\r\n\r\n const query = useQuery({\r\n queryKey: specsSettingsKeys.specStats(projectPath),\r\n queryFn: () => getSpecStats(projectPath),\r\n staleTime,\r\n enabled,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// Specs List Hook\r\n// ========================================\r\n\r\nexport interface UseSpecsListOptions {\r\n projectPath?: string;\r\n enabled?: boolean;\r\n staleTime?: number;\r\n}\r\n\r\nexport interface UseSpecsListReturn {\r\n data: SpecsListResponse | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\n/**\r\n * Hook to fetch specs list for all dimensions\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useSpecsList(options: UseSpecsListOptions = {}): UseSpecsListReturn {\r\n const { projectPath, enabled = true, staleTime = STALE_TIME } = options;\r\n\r\n const query = useQuery({\r\n queryKey: specsSettingsKeys.specsList(projectPath),\r\n queryFn: () => getSpecsList(projectPath),\r\n staleTime,\r\n enabled,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// Rebuild Spec Index Mutation Hook\r\n// ========================================\r\n\r\nexport interface UseRebuildSpecIndexOptions {\r\n projectPath?: string;\r\n}\r\n\r\n/**\r\n * Hook to rebuild spec index\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useRebuildSpecIndex(options: UseRebuildSpecIndexOptions = {}) {\r\n const { projectPath } = options;\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: () => rebuildSpecIndex(projectPath),\r\n onSuccess: () => {\r\n // Invalidate specs list and stats queries to refresh data\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specStats(projectPath) });\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specsList(projectPath) });\r\n },\r\n });\r\n\r\n return {\r\n mutate: mutation.mutate,\r\n mutateAsync: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n data: mutation.data,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Update Spec Frontmatter Mutation Hook\r\n// ========================================\r\n\r\nexport interface UseUpdateSpecFrontmatterOptions {\r\n projectPath?: string;\r\n}\r\n\r\n/**\r\n * Hook to update spec frontmatter (e.g., toggle readMode)\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useUpdateSpecFrontmatter(options: UseUpdateSpecFrontmatterOptions = {}) {\r\n const { projectPath } = options;\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ file, readMode }: { file: string; readMode: string }) =>\r\n updateSpecFrontmatter(file, readMode, projectPath),\r\n onSuccess: () => {\r\n // Invalidate specs list and stats to refresh data\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specStats(projectPath) });\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specsList(projectPath) });\r\n },\r\n });\r\n\r\n return {\r\n mutate: mutation.mutate,\r\n mutateAsync: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n data: mutation.data,\r\n };\r\n}\r\n"],"names":["systemSettingsKeys","STALE_TIME","useChineseResponseStatus","query","useQuery","fetchChineseResponseStatus","useToggleChineseResponse","queryClient","useQueryClient","mutation","useMutation","enabled","target","toggleChineseResponse","useWindowsPlatformStatus","fetchWindowsPlatformStatus","useToggleWindowsPlatform","toggleWindowsPlatform","useCodexCliEnhancementStatus","fetchCodexCliEnhancementStatus","useToggleCodexCliEnhancement","toggleCodexCliEnhancement","useRefreshCodexCliEnhancement","refreshCodexCliEnhancement","useCcwInstallStatus","fetchAggregatedStatus","_a","useCliToolStatus","fetchCliToolStatus","useCcwInstallations","fetchCcwInstallations","useUpgradeCcwInstallation","path","upgradeCcwInstallation","useExportSettings","exportSettings","useImportSettings","data","options","importSettings","specsSettingsKeys","projectPath","useSystemSettings","getSystemSettings","useInstallRecommendedHooks","hookIds","scope","installRecommendedHooks","useSpecStats","staleTime","getSpecStats","useSpecsList","getSpecsList","useRebuildSpecIndex","rebuildSpecIndex"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useSystemSettings-BjMgsNSF.js","sources":["../../src/hooks/useSystemSettings.ts"],"sourcesContent":["// ========================================\r\n// useSystemSettings Hook\r\n// ========================================\r\n// TanStack Query hooks for system settings (language, install status, tool status)\r\n\r\nimport { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';\r\nimport {\r\n fetchChineseResponseStatus,\r\n toggleChineseResponse,\r\n fetchWindowsPlatformStatus,\r\n toggleWindowsPlatform,\r\n fetchCodexCliEnhancementStatus,\r\n toggleCodexCliEnhancement,\r\n refreshCodexCliEnhancement,\r\n fetchAggregatedStatus,\r\n fetchCliToolStatus,\r\n fetchCcwInstallations,\r\n upgradeCcwInstallation,\r\n exportSettings,\r\n importSettings,\r\n type ChineseResponseStatus,\r\n type WindowsPlatformStatus,\r\n type CodexCliEnhancementStatus,\r\n type CcwInstallStatus,\r\n type CcwInstallationManifest,\r\n type ExportedSettings,\r\n type ImportOptions,\r\n} from '../lib/api';\r\n\r\n// Query key factory\r\nexport const systemSettingsKeys = {\r\n all: ['systemSettings'] as const,\r\n chineseResponse: () => [...systemSettingsKeys.all, 'chineseResponse'] as const,\r\n windowsPlatform: () => [...systemSettingsKeys.all, 'windowsPlatform'] as const,\r\n codexCliEnhancement: () => [...systemSettingsKeys.all, 'codexCliEnhancement'] as const,\r\n aggregatedStatus: () => [...systemSettingsKeys.all, 'aggregatedStatus'] as const,\r\n cliToolStatus: () => [...systemSettingsKeys.all, 'cliToolStatus'] as const,\r\n ccwInstallations: () => [...systemSettingsKeys.all, 'ccwInstallations'] as const,\r\n exportSettings: () => [...systemSettingsKeys.all, 'exportSettings'] as const,\r\n};\r\n\r\nconst STALE_TIME = 60 * 1000; // 1 minute\r\n\r\n// ========================================\r\n// Chinese Response Hooks\r\n// ========================================\r\n\r\nexport interface UseChineseResponseStatusReturn {\r\n data: ChineseResponseStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useChineseResponseStatus(): UseChineseResponseStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.chineseResponse(),\r\n queryFn: fetchChineseResponseStatus,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useToggleChineseResponse() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ enabled, target }: { enabled: boolean; target: 'claude' | 'codex' }) =>\r\n toggleChineseResponse(enabled, target),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.chineseResponse() });\r\n },\r\n });\r\n\r\n return {\r\n toggle: (enabled: boolean, target: 'claude' | 'codex') =>\r\n mutation.mutateAsync({ enabled, target }),\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Windows Platform Hooks\r\n// ========================================\r\n\r\nexport interface UseWindowsPlatformStatusReturn {\r\n data: WindowsPlatformStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useWindowsPlatformStatus(): UseWindowsPlatformStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.windowsPlatform(),\r\n queryFn: fetchWindowsPlatformStatus,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useToggleWindowsPlatform() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (enabled: boolean) => toggleWindowsPlatform(enabled),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.windowsPlatform() });\r\n },\r\n });\r\n\r\n return {\r\n toggle: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Codex CLI Enhancement Hooks\r\n// ========================================\r\n\r\nexport interface UseCodexCliEnhancementStatusReturn {\r\n data: CodexCliEnhancementStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCodexCliEnhancementStatus(): UseCodexCliEnhancementStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.codexCliEnhancement(),\r\n queryFn: fetchCodexCliEnhancementStatus,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useToggleCodexCliEnhancement() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (enabled: boolean) => toggleCodexCliEnhancement(enabled),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.codexCliEnhancement() });\r\n },\r\n });\r\n\r\n return {\r\n toggle: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\nexport function useRefreshCodexCliEnhancement() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: () => refreshCodexCliEnhancement(),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.codexCliEnhancement() });\r\n },\r\n });\r\n\r\n return {\r\n refresh: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Aggregated Status / CCW Install Hooks\r\n// ========================================\r\n\r\nexport interface UseCcwInstallStatusReturn {\r\n data: CcwInstallStatus | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCcwInstallStatus(): UseCcwInstallStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.aggregatedStatus(),\r\n queryFn: fetchAggregatedStatus,\r\n staleTime: 5 * 60 * 1000, // 5 minutes\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data?.ccwInstall,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// CLI Tool Status Hooks\r\n// ========================================\r\n\r\nexport interface UseCliToolStatusReturn {\r\n data: Record<string, { available: boolean; path?: string; version?: string }> | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCliToolStatus(): UseCliToolStatusReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.cliToolStatus(),\r\n queryFn: fetchCliToolStatus,\r\n staleTime: 2 * 60 * 1000, // 2 minutes\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// CCW Installations Hooks\r\n// ========================================\r\n\r\nexport interface UseCcwInstallationsReturn {\r\n installations: CcwInstallationManifest[];\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\nexport function useCcwInstallations(): UseCcwInstallationsReturn {\r\n const query = useQuery({\r\n queryKey: systemSettingsKeys.ccwInstallations(),\r\n queryFn: fetchCcwInstallations,\r\n staleTime: 5 * 60 * 1000, // 5 minutes\r\n retry: 1,\r\n });\r\n\r\n return {\r\n installations: query.data?.installations ?? [],\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\nexport function useUpgradeCcwInstallation() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (path?: string) => upgradeCcwInstallation(path),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.ccwInstallations() });\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.aggregatedStatus() });\r\n },\r\n });\r\n\r\n return {\r\n upgrade: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Settings Export/Import Hooks\r\n// ========================================\r\n\r\nexport function useExportSettings() {\r\n const mutation = useMutation({\r\n mutationFn: exportSettings,\r\n });\r\n\r\n return {\r\n exportSettings: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\nexport function useImportSettings() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ data, options }: { data: ExportedSettings; options?: ImportOptions }) =>\r\n importSettings(data, options),\r\n onSuccess: () => {\r\n // Invalidate all system settings queries to refresh the UI\r\n queryClient.invalidateQueries({ queryKey: systemSettingsKeys.all });\r\n },\r\n });\r\n\r\n return {\r\n importSettings: (data: ExportedSettings, options?: ImportOptions) =>\r\n mutation.mutateAsync({ data, options }),\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Specs Settings Hooks\r\n// ========================================\r\n\r\nimport {\r\n getSystemSettings,\r\n updateSystemSettings,\r\n installRecommendedHooks,\r\n getSpecStats,\r\n getSpecsList,\r\n rebuildSpecIndex,\r\n updateSpecFrontmatter,\r\n type SystemSettings,\r\n type UpdateSystemSettingsInput,\r\n type SpecStats,\r\n type SpecsListResponse,\r\n} from '../lib/api';\r\n\r\n// Query keys for specs settings\r\nexport const specsSettingsKeys = {\r\n all: ['specsSettings'] as const,\r\n systemSettings: () => [...specsSettingsKeys.all, 'systemSettings'] as const,\r\n specStats: (projectPath?: string) => [...specsSettingsKeys.all, 'specStats', projectPath] as const,\r\n specsList: (projectPath?: string) => [...specsSettingsKeys.all, 'specsList', projectPath] as const,\r\n};\r\n\r\n// ========================================\r\n// System Settings Query Hook\r\n// ========================================\r\n\r\nexport interface UseSystemSettingsReturn {\r\n data: SystemSettings | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\n/**\r\n * Hook to fetch system settings (injection control, personal spec defaults, recommended hooks)\r\n */\r\nexport function useSystemSettings(): UseSystemSettingsReturn {\r\n const query = useQuery({\r\n queryKey: specsSettingsKeys.systemSettings(),\r\n queryFn: getSystemSettings,\r\n staleTime: STALE_TIME,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// Update System Settings Mutation Hook\r\n// ========================================\r\n\r\nexport function useUpdateSystemSettings() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: (data: UpdateSystemSettingsInput) => updateSystemSettings(data),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.systemSettings() });\r\n },\r\n });\r\n\r\n return {\r\n updateSettings: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Install Recommended Hooks Mutation Hook\r\n// ========================================\r\n\r\nexport function useInstallRecommendedHooks() {\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ hookIds, scope }: { hookIds: string[]; scope?: 'global' | 'project' }) =>\r\n installRecommendedHooks(hookIds, scope),\r\n onSuccess: () => {\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.systemSettings() });\r\n },\r\n });\r\n\r\n return {\r\n installHooks: (hookIds: string[], scope?: 'global' | 'project') =>\r\n mutation.mutateAsync({ hookIds, scope }),\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n data: mutation.data,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Spec Stats Query Hook\r\n// ========================================\r\n\r\nexport interface UseSpecStatsOptions {\r\n projectPath?: string;\r\n enabled?: boolean;\r\n staleTime?: number;\r\n}\r\n\r\nexport interface UseSpecStatsReturn {\r\n data: SpecStats | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\n/**\r\n * Hook to fetch spec statistics (dimensions count, injection length info)\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useSpecStats(options: UseSpecStatsOptions = {}): UseSpecStatsReturn {\r\n const { projectPath, enabled = true, staleTime = STALE_TIME } = options;\r\n\r\n const query = useQuery({\r\n queryKey: specsSettingsKeys.specStats(projectPath),\r\n queryFn: () => getSpecStats(projectPath),\r\n staleTime,\r\n enabled,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// Specs List Hook\r\n// ========================================\r\n\r\nexport interface UseSpecsListOptions {\r\n projectPath?: string;\r\n enabled?: boolean;\r\n staleTime?: number;\r\n}\r\n\r\nexport interface UseSpecsListReturn {\r\n data: SpecsListResponse | undefined;\r\n isLoading: boolean;\r\n error: Error | null;\r\n refetch: () => void;\r\n}\r\n\r\n/**\r\n * Hook to fetch specs list for all dimensions\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useSpecsList(options: UseSpecsListOptions = {}): UseSpecsListReturn {\r\n const { projectPath, enabled = true, staleTime = STALE_TIME } = options;\r\n\r\n const query = useQuery({\r\n queryKey: specsSettingsKeys.specsList(projectPath),\r\n queryFn: () => getSpecsList(projectPath),\r\n staleTime,\r\n enabled,\r\n retry: 1,\r\n });\r\n\r\n return {\r\n data: query.data,\r\n isLoading: query.isLoading,\r\n error: query.error,\r\n refetch: () => { query.refetch(); },\r\n };\r\n}\r\n\r\n// ========================================\r\n// Rebuild Spec Index Mutation Hook\r\n// ========================================\r\n\r\nexport interface UseRebuildSpecIndexOptions {\r\n projectPath?: string;\r\n}\r\n\r\n/**\r\n * Hook to rebuild spec index\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useRebuildSpecIndex(options: UseRebuildSpecIndexOptions = {}) {\r\n const { projectPath } = options;\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: () => rebuildSpecIndex(projectPath),\r\n onSuccess: () => {\r\n // Invalidate specs list and stats queries to refresh data\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specStats(projectPath) });\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specsList(projectPath) });\r\n },\r\n });\r\n\r\n return {\r\n mutate: mutation.mutate,\r\n mutateAsync: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n data: mutation.data,\r\n };\r\n}\r\n\r\n// ========================================\r\n// Update Spec Frontmatter Mutation Hook\r\n// ========================================\r\n\r\nexport interface UseUpdateSpecFrontmatterOptions {\r\n projectPath?: string;\r\n}\r\n\r\n/**\r\n * Hook to update spec frontmatter (e.g., toggle readMode)\r\n * @param options - Options including projectPath for workspace isolation\r\n */\r\nexport function useUpdateSpecFrontmatter(options: UseUpdateSpecFrontmatterOptions = {}) {\r\n const { projectPath } = options;\r\n const queryClient = useQueryClient();\r\n\r\n const mutation = useMutation({\r\n mutationFn: ({ file, readMode }: { file: string; readMode: string }) =>\r\n updateSpecFrontmatter(file, readMode, projectPath),\r\n onSuccess: () => {\r\n // Invalidate specs list and stats to refresh data\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specStats(projectPath) });\r\n queryClient.invalidateQueries({ queryKey: specsSettingsKeys.specsList(projectPath) });\r\n },\r\n });\r\n\r\n return {\r\n mutate: mutation.mutate,\r\n mutateAsync: mutation.mutateAsync,\r\n isPending: mutation.isPending,\r\n error: mutation.error,\r\n data: mutation.data,\r\n };\r\n}\r\n"],"names":["systemSettingsKeys","STALE_TIME","useChineseResponseStatus","query","useQuery","fetchChineseResponseStatus","useToggleChineseResponse","queryClient","useQueryClient","mutation","useMutation","enabled","target","toggleChineseResponse","useWindowsPlatformStatus","fetchWindowsPlatformStatus","useToggleWindowsPlatform","toggleWindowsPlatform","useCodexCliEnhancementStatus","fetchCodexCliEnhancementStatus","useToggleCodexCliEnhancement","toggleCodexCliEnhancement","useRefreshCodexCliEnhancement","refreshCodexCliEnhancement","useCcwInstallStatus","fetchAggregatedStatus","_a","useCliToolStatus","fetchCliToolStatus","useCcwInstallations","fetchCcwInstallations","useUpgradeCcwInstallation","path","upgradeCcwInstallation","useExportSettings","exportSettings","useImportSettings","data","options","importSettings","specsSettingsKeys","projectPath","useSystemSettings","getSystemSettings","useInstallRecommendedHooks","hookIds","scope","installRecommendedHooks","useSpecStats","staleTime","getSpecStats","useSpecsList","getSpecsList","useRebuildSpecIndex","rebuildSpecIndex"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import{O as a}from"./index-
|
|
1
|
+
import{O as a}from"./index-BUol9HDD.js";/**
|
|
2
2
|
* @license lucide-react v0.460.0 - ISC
|
|
3
3
|
*
|
|
4
4
|
* This source code is licensed under the ISC license.
|
|
5
5
|
* See the LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/const p=a("WandSparkles",[["path",{d:"m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72",key:"ul74o6"}],["path",{d:"m14 7 3 3",key:"1r5n42"}],["path",{d:"M5 6v4",key:"ilb8ba"}],["path",{d:"M19 14v4",key:"blhpug"}],["path",{d:"M10 2v2",key:"7u0qdc"}],["path",{d:"M7 8H3",key:"zfb6yr"}],["path",{d:"M21 16h-4",key:"1cnmox"}],["path",{d:"M11 3H9",key:"1obp7u"}]]);export{p as W};
|
|
7
|
-
//# sourceMappingURL=wand-sparkles-
|
|
7
|
+
//# sourceMappingURL=wand-sparkles-CLhyYWa7.js.map
|
package/ccw/frontend/dist/assets/{wand-sparkles-DZV_3lPr.js.map → wand-sparkles-CLhyYWa7.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"wand-sparkles-
|
|
1
|
+
{"version":3,"file":"wand-sparkles-CLhyYWa7.js","sources":["../../../../node_modules/lucide-react/dist/esm/icons/wand-sparkles.js"],"sourcesContent":["/**\n * @license lucide-react v0.460.0 - ISC\n *\n * This source code is licensed under the ISC license.\n * See the LICENSE file in the root directory of this source tree.\n */\n\nimport createLucideIcon from '../createLucideIcon.js';\n\nconst WandSparkles = createLucideIcon(\"WandSparkles\", [\n [\n \"path\",\n {\n d: \"m21.64 3.64-1.28-1.28a1.21 1.21 0 0 0-1.72 0L2.36 18.64a1.21 1.21 0 0 0 0 1.72l1.28 1.28a1.2 1.2 0 0 0 1.72 0L21.64 5.36a1.2 1.2 0 0 0 0-1.72\",\n key: \"ul74o6\"\n }\n ],\n [\"path\", { d: \"m14 7 3 3\", key: \"1r5n42\" }],\n [\"path\", { d: \"M5 6v4\", key: \"ilb8ba\" }],\n [\"path\", { d: \"M19 14v4\", key: \"blhpug\" }],\n [\"path\", { d: \"M10 2v2\", key: \"7u0qdc\" }],\n [\"path\", { d: \"M7 8H3\", key: \"zfb6yr\" }],\n [\"path\", { d: \"M21 16h-4\", key: \"1cnmox\" }],\n [\"path\", { d: \"M11 3H9\", key: \"1obp7u\" }]\n]);\n\nexport { WandSparkles as default };\n//# sourceMappingURL=wand-sparkles.js.map\n"],"names":["WandSparkles","createLucideIcon"],"mappings":"wCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GASK,MAACA,EAAeC,EAAiB,eAAgB,CACpD,CACE,OACA,CACE,EAAG,gJACH,IAAK,QACX,CACA,EACE,CAAC,OAAQ,CAAE,EAAG,YAAa,IAAK,QAAQ,CAAE,EAC1C,CAAC,OAAQ,CAAE,EAAG,SAAU,IAAK,QAAQ,CAAE,EACvC,CAAC,OAAQ,CAAE,EAAG,WAAY,IAAK,QAAQ,CAAE,EACzC,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,QAAQ,CAAE,EACxC,CAAC,OAAQ,CAAE,EAAG,SAAU,IAAK,QAAQ,CAAE,EACvC,CAAC,OAAQ,CAAE,EAAG,YAAa,IAAK,QAAQ,CAAE,EAC1C,CAAC,OAAQ,CAAE,EAAG,UAAW,IAAK,QAAQ,CAAE,CAC1C,CAAC","x_google_ignoreList":[0]}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
10
|
<title>CCW Dashboard</title>
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-BUol9HDD.js"></script>
|
|
12
12
|
<link rel="stylesheet" crossorigin href="/assets/index-BoqylFO4.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body class="font-sans bg-background text-foreground antialiased">
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-code-workflow",
|
|
3
|
-
"version": "7.2.
|
|
3
|
+
"version": "7.2.29",
|
|
4
4
|
"description": "JSON-driven multi-agent development framework with intelligent CLI orchestration (Gemini/Qwen/Codex), context-first architecture, and automated workflow execution",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "ccw/dist/index.js",
|