cc-viewer 1.4.8 → 1.4.10

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.
@@ -29,4 +29,13 @@ body{margin:0;background-color:#0d0d0d}*{scrollbar-width:thin;scrollbar-color:#3
29
29
  * The original design remains. The terminal itself
30
30
  * has been extended to include xterm CSI codes, among
31
31
  * other features.
32
- */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}._terminalPanel_1slw1_1{height:100%;display:flex;flex-direction:column;background:#0a0a0a}._terminalContainer_1slw1_8{flex:1;overflow:hidden;padding:4px 8px;touch-action:none;overscroll-behavior:contain}._virtualKeybar_1slw1_16{display:flex;gap:6px;padding:8px 10px;background:#111;border-top:1px solid #222;overflow-x:auto;flex-shrink:0;-webkit-overflow-scrolling:touch}._virtualKey_1slw1_16{flex-shrink:0;padding:12px 20px;border:1px solid #333;border-radius:8px;background:#1a1a1a;color:#ccc;font-size:15px;font-family:Menlo,Monaco,monospace;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation;min-width:44px;min-height:44px;display:flex;align-items:center;justify-content:center}._virtualKey_1slw1_16:active{background:#333;border-color:#555;color:#fff}._centerEmpty_1o094_1{display:flex;align-items:center;justify-content:center;height:100%}._container_1o094_8{flex:1;overflow:auto;padding:16px 24px;display:flex;flex-direction:column;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}._sessionDividerText_1o094_18{font-size:11px;color:#555}._lastResponseLabel_1o094_23{font-size:11px}._splitContainer_1o094_27{display:flex;flex-direction:row;height:100%;overflow:hidden}._chatSection_1o094_34{display:flex;flex-direction:column;min-width:0;overflow:hidden}._vResizer_1o094_41{width:5px;background:#1a1a1a;cursor:col-resize;flex-shrink:0;border-left:1px solid #2a2a2a;border-right:1px solid #2a2a2a;transition:background .15s}._vResizer_1o094_41:hover{background:#333}._chatInputBar_1o094_55{display:flex;align-items:flex-end;gap:8px;padding:10px 16px;background:#111;border-top:1px solid #2a2a2a;flex-shrink:0}._chatInputWrapper_1o094_65{flex:1;display:flex;flex-direction:column;background:#1a1a1a;border:1px solid #333;border-radius:12px;transition:border-color .2s;overflow:hidden}._chatInputWrapper_1o094_65:focus-within{border-color:#555}._chatTextareaWrap_1o094_80{position:relative;flex:1}._chatTextarea_1o094_80{width:100%;min-height:22px;max-height:120px;padding:10px 14px;background:transparent;color:#e0e0e0;border:none;outline:none;resize:none;font-size:14px;line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}._chatTextarea_1o094_80::placeholder{color:#555}._chatInputHint_1o094_104{font-size:11px;color:#444;padding:0 14px 6px;-webkit-user-select:none;user-select:none}._chatSendBtn_1o094_111{width:36px;height:36px;border-radius:10px;border:none;background:#4a9eff;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .15s,opacity .15s}._chatSendBtn_1o094_111:hover{background:#3a8eef}._chatSendBtn_1o094_111:disabled{opacity:.35;cursor:default}._chatSendBtn_1o094_111 svg{width:18px;height:18px}._messageListWrap_1o094_140{position:relative;flex:1;min-height:0;display:flex;flex-direction:column}._stickyBottomBtn_1o094_148{position:absolute;left:0;bottom:0;display:flex;flex-direction:column;align-items:center;gap:2px;padding:8px 18px;height:60px;justify-content:center;border-radius:0;border:none;background:none;color:#999;font-size:12px;cursor:pointer;transition:color .15s;z-index:10;box-shadow:none}._stickyBottomBtn_1o094_148 span{background:#00000080;padding:2px 10px;border-radius:10px}._stickyBottomBtn_1o094_148:hover{color:#fff;background:none}._ptyPromptBubble_1o094_181{margin:8px 0;padding:12px 16px;border-radius:12px;border:1px solid #3a3a3a;background:#161616;animation:_ptyPromptFadeIn_1o094_1 .25s ease-out}._ptyPromptResolved_1o094_190{opacity:.55}@keyframes _ptyPromptFadeIn_1o094_1{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}._ptyPromptQuestion_1o094_199{font-size:13px;color:#ccc;margin-bottom:10px;line-height:1.4}._ptyPromptOptions_1o094_206{display:flex;flex-wrap:wrap;gap:8px}._ptyPromptOption_1o094_206{padding:6px 14px;border-radius:18px;border:1px solid #3a3a3a;background:#1a1a1a;color:#bbb;font-size:12px;cursor:pointer;transition:background .15s,color .15s,border-color .15s;white-space:nowrap}._ptyPromptOption_1o094_206:hover{background:#2a2a2a;color:#eee;border-color:#555}._ptyPromptOptionPrimary_1o094_230{padding:6px 14px;border-radius:18px;border:1px solid #4a9eff;background:#4a9eff26;color:#4a9eff;font-size:12px;cursor:pointer;transition:background .15s,color .15s,border-color .15s;white-space:nowrap}._ptyPromptOptionPrimary_1o094_230:hover{background:#4a9eff40;color:#6ab4ff;border-color:#6ab4ff}._ptyPromptOptionChosen_1o094_248{padding:6px 14px;border-radius:18px;border:1px solid #4a9eff;background:#4a9eff33;color:#4a9eff;font-size:12px;cursor:default;white-space:nowrap}._ptyPromptOptionDimmed_1o094_259{padding:6px 14px;border-radius:18px;border:1px solid #2a2a2a;background:transparent;color:#444;font-size:12px;cursor:default;white-space:nowrap}._ghostText_1o094_270{position:absolute;top:0;left:0;right:0;padding:10px 14px;color:#444;font-size:14px;line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;pointer-events:none;white-space:pre-wrap;overflow:hidden;max-height:120px}._suggestionChip_1o094_286{display:flex;align-items:center;gap:8px;padding:8px 14px;background:#1a1a1a;border-top:1px solid #2a2a2a;cursor:pointer;flex-shrink:0;transition:background .15s}._suggestionChip_1o094_286:hover{background:#222}._suggestionChipText_1o094_302{flex:1;color:#555;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._suggestionChipAction_1o094_311{color:#4a9eff;font-size:14px;flex-shrink:0}._resizer_yamj2_1{width:6px;cursor:col-resize;background:#1f1f1f;flex-shrink:0;transition:background .2s}._resizer_yamj2_1:hover{background:#3b82f6}._layout_t1dhs_1{height:100vh;overflow:hidden}._header_t1dhs_6{background:#111;border-bottom:1px solid #1f1f1f;padding:0 24px;height:60px;line-height:60px}._content_t1dhs_14{flex:1;overflow:hidden}._mainContainer_t1dhs_19{display:flex;height:100%}._leftPanel_t1dhs_24{flex-shrink:0;border-right:1px solid #1f1f1f;display:flex;flex-direction:column;background:#0a0a0a}._leftPanelHeader_t1dhs_32{padding:10px 16px;border-bottom:1px solid #1f1f1f;font-size:13px;color:#9ca3af;font-weight:500;display:flex;justify-content:space-between;align-items:center}._leftPanelCount_t1dhs_43{font-size:12px;color:#555;font-weight:400}._leftPanelBody_t1dhs_49{flex:1;overflow:hidden}._rightPanel_t1dhs_54{flex:1;overflow:hidden;background:#0d0d0d}._modalActions_t1dhs_60{margin-bottom:12px}._spinCenter_t1dhs_64{text-align:center;padding:40px}._emptyCenter_t1dhs_69{text-align:center;color:#999;padding:40px}._logCheckbox_t1dhs_75{margin-right:8px}._logListContainer_t1dhs_79{background:#0d0d0d;border-radius:8px;overflow:hidden}._logListItem_t1dhs_85{cursor:pointer;padding:8px 12px;border-bottom:1px solid #222}._logItemRow_t1dhs_91{display:flex;align-items:center;width:100%;justify-content:space-between;flex-wrap:nowrap;gap:12px}._logItemRow_t1dhs_91>span:first-child{display:flex;align-items:center;flex:1;min-width:0;overflow:hidden}._logFileName_t1dhs_108{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._logItemRow_t1dhs_91>span:last-child{display:flex;align-items:center;flex-shrink:0;gap:8px}._logFileIcon_t1dhs_121{margin-right:8px;color:#3b82f6;flex-shrink:0}._loadingOverlay_t1dhs_127{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#000000bf;display:flex;align-items:center;justify-content:center;z-index:9999}._loadingText_t1dhs_140{color:#fff;font-size:16px;font-weight:700}._footer_t1dhs_146{height:18px;background:#000;display:flex;align-items:center;justify-content:flex-end;padding:0 12px;flex-shrink:0}._footerRight_t1dhs_156{display:flex;align-items:center;gap:6px;font-size:11px;color:#555}._footerText_t1dhs_164{color:#444;margin-right:2px}._footerLink_t1dhs_169{display:inline-flex;align-items:center;gap:3px;color:#555;text-decoration:none}._footerLink_t1dhs_169:hover{color:#888}._footerIcon_t1dhs_181{width:12px;height:12px}._footerDivider_t1dhs_186{color:#333}._footerText_t1dhs_164{color:#555}._guideContainer_t1dhs_194{display:flex;align-items:center;justify-content:center;height:100%;background:#0a0a0a}._guideContent_t1dhs_202{max-width:560px;padding:40px}._guideTitle_t1dhs_207{font-size:20px;font-weight:600;color:#e0e0e0;margin:0 0 28px}._guideStep_t1dhs_214{display:flex;gap:14px;margin-bottom:22px}._guideStepNum_t1dhs_220{flex-shrink:0;width:24px;height:24px;border-radius:50%;background:#1a1a2e;color:#7c8aff;font-size:13px;font-weight:600;display:flex;align-items:center;justify-content:center;margin-top:1px}._guideStepBody_t1dhs_235{flex:1;min-width:0}._guideText_t1dhs_240{color:#aaa;font-size:14px;line-height:1.6;margin:0 0 8px}._guideCode_t1dhs_247{display:block;background:#141414;border:1px solid #252525;border-radius:6px;padding:10px 14px;color:#8b9cf7;font-size:13px;line-height:1.5;word-break:break-all;white-space:pre-wrap}._mobileChatOverlay_t1dhs_260{position:absolute;top:0;right:0;bottom:0;left:0;transform:translate(100%);transition:transform .3s ease;z-index:100;background:#0a0a0a;display:flex;flex-direction:column;overflow:hidden}._mobileChatOverlayVisible_t1dhs_272{transform:translate(0)}._mobileChatInner_t1dhs_276{flex:1;min-height:0;display:flex;flex-direction:column;zoom:.6}
32
+ */.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;right:0;left:0;top:0;bottom:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;left:0;top:0;bottom:0;right:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}._terminalPanel_1slw1_1{height:100%;display:flex;flex-direction:column;background:#0a0a0a}._terminalContainer_1slw1_8{flex:1;overflow:hidden;padding:4px 8px;touch-action:none;overscroll-behavior:contain}._virtualKeybar_1slw1_16{display:flex;gap:6px;padding:8px 10px;background:#111;border-top:1px solid #222;overflow-x:auto;flex-shrink:0;-webkit-overflow-scrolling:touch}._virtualKey_1slw1_16{flex-shrink:0;padding:12px 20px;border:1px solid #333;border-radius:8px;background:#1a1a1a;color:#ccc;font-size:15px;font-family:Menlo,Monaco,monospace;cursor:pointer;-webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent;touch-action:manipulation;min-width:44px;min-height:44px;display:flex;align-items:center;justify-content:center}._virtualKey_1slw1_16:active{background:#333;border-color:#555;color:#fff}._fileExplorer_1ae99_1{width:240px;flex-shrink:0;background:#111;border-right:1px solid #2a2a2a;display:flex;flex-direction:column;overflow:hidden;-webkit-user-select:none;user-select:none}._header_1ae99_12{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid #2a2a2a;flex-shrink:0}._headerTitle_1ae99_21{font-size:11px;font-weight:600;color:#888;text-transform:uppercase;letter-spacing:.5px}._collapseBtn_1ae99_29{width:20px;height:20px;border:none;background:none;color:#666;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:0}._collapseBtn_1ae99_29:hover{color:#ccc;background:#2a2a2a}._treeContainer_1ae99_48{flex:1;overflow:auto;padding:4px 0}._treeItem_1ae99_54{display:flex;align-items:center;height:26px;padding:0 8px;cursor:pointer;color:#ccc;font-size:13px;white-space:nowrap;transition:background .1s}._treeItem_1ae99_54:hover{background:#1a1a1a}._arrow_1ae99_70{width:16px;flex-shrink:0;font-size:10px;color:#666;text-align:center}._icon_1ae99_78{width:16px;height:16px;flex-shrink:0;margin-right:6px;display:flex;align-items:center;justify-content:center}._fileName_1ae99_88{overflow:hidden;text-overflow:ellipsis}._loading_1ae99_93{color:#555;font-size:12px;padding:4px 8px}._error_1ae99_99{color:#ff6b6b;font-size:12px;padding:4px 8px}pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}/*!
33
+ Theme: GitHub Dark
34
+ Description: Dark theme as seen on github.com
35
+ Author: github.com
36
+ Maintainer: @Hirse
37
+ Updated: 2021-05-15
38
+
39
+ Outdated base version: https://github.com/primer/github-syntax-dark
40
+ Current colors taken from GitHub's CSS
41
+ */.hljs{color:#c9d1d9;background:#0d1117}.hljs-doctag,.hljs-keyword,.hljs-meta .hljs-keyword,.hljs-template-tag,.hljs-template-variable,.hljs-type,.hljs-variable.language_{color:#ff7b72}.hljs-title,.hljs-title.class_,.hljs-title.class_.inherited__,.hljs-title.function_{color:#d2a8ff}.hljs-attr,.hljs-attribute,.hljs-literal,.hljs-meta,.hljs-number,.hljs-operator,.hljs-variable,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-id{color:#79c0ff}.hljs-regexp,.hljs-string,.hljs-meta .hljs-string{color:#a5d6ff}.hljs-built_in,.hljs-symbol{color:#ffa657}.hljs-comment,.hljs-code,.hljs-formula{color:#8b949e}.hljs-name,.hljs-quote,.hljs-selector-tag,.hljs-selector-pseudo{color:#7ee787}.hljs-subst{color:#c9d1d9}.hljs-section{color:#1f6feb;font-weight:700}.hljs-bullet{color:#f2cc60}.hljs-emphasis{color:#c9d1d9;font-style:italic}.hljs-strong{color:#c9d1d9;font-weight:700}.hljs-addition{color:#aff5b4;background-color:#033a16}.hljs-deletion{color:#ffdcd7;background-color:#67060c}._fileContentView_1sb22_1{display:flex;flex-direction:column;height:100%;background:#0d0d0d}._header_1sb22_8{display:flex;align-items:center;justify-content:space-between;padding:10px 16px;border-bottom:1px solid #2a2a2a;background:#111;flex-shrink:0}._headerLeft_1sb22_18{display:flex;align-items:center;gap:8px;flex:1;min-width:0}._backBtn_1sb22_26{width:28px;height:28px;border:none;background:none;color:#666;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:6px;padding:0;flex-shrink:0;transition:background .15s,color .15s}._backBtn_1sb22_26:hover{color:#ccc;background:#1a1a1a}._filePath_1sb22_47{font-size:13px;color:#ccc;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._fileSize_1sb22_55{font-size:11px;color:#666;flex-shrink:0}._contentContainer_1sb22_61{flex:1;overflow:auto;background:#0d0d0d}._codeBlock_1sb22_67{min-height:100%}._codeContent_1sb22_71{padding:0;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;font-size:13px;line-height:1.5;color:#e0e0e0;overflow-x:auto;-moz-tab-size:2;tab-size:2;margin:0}._codeContent_1sb22_71 code{font-family:inherit;font-size:inherit;line-height:inherit;background:none;padding:0;display:block}._codeLine_1sb22_91{display:flex;min-height:1.5em}._codeLine_1sb22_91:hover{background:#ffffff08}._lineNumber_1sb22_100{flex-shrink:0;width:50px;padding:0 16px;text-align:right;color:#555;-webkit-user-select:none;user-select:none;border-right:1px solid #2a2a2a}._lineContent_1sb22_110{flex:1;padding:0 16px;white-space:pre;overflow-x:visible}._loading_1sb22_117{display:flex;align-items:center;justify-content:center;height:100%;color:#666;font-size:14px}._error_1sb22_126{display:flex;align-items:center;justify-content:center;height:100%;color:#ff6b6b;font-size:14px}._gitChanges_1fy65_1{width:240px;flex-shrink:0;background:#111;border-right:1px solid #2a2a2a;display:flex;flex-direction:column;overflow:hidden;-webkit-user-select:none;user-select:none}._header_1fy65_12{display:flex;align-items:center;justify-content:space-between;padding:10px 12px;border-bottom:1px solid #2a2a2a;flex-shrink:0}._headerTitle_1fy65_21{font-size:11px;font-weight:600;color:#888;text-transform:uppercase;letter-spacing:.5px}._collapseBtn_1fy65_29{width:20px;height:20px;border:none;background:none;color:#666;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:0}._collapseBtn_1fy65_29:hover{color:#ccc;background:#2a2a2a}._changesContainer_1fy65_48{flex:1;overflow:auto;padding:4px 0}._changeItem_1fy65_54{display:flex;align-items:center;height:28px;padding:0 12px;cursor:pointer;color:#ccc;font-size:13px;white-space:nowrap;transition:background .1s;gap:8px}._changeItem_1fy65_54:hover{background:#1a1a1a}._status_1fy65_71{width:16px;flex-shrink:0;font-size:11px;font-weight:600;text-align:center}._icon_1fy65_79{width:16px;height:16px;flex-shrink:0;display:flex;align-items:center;justify-content:center}._fileName_1fy65_88{overflow:hidden;text-overflow:ellipsis;flex:1}._loading_1fy65_94{color:#555;font-size:12px;padding:8px 12px}._error_1fy65_100{color:#ff6b6b;font-size:12px;padding:8px 12px}._empty_1fy65_106{color:#666;font-size:12px;padding:8px 12px;text-align:center}._fullFileDiffView_e9dmx_1{width:100%;height:100%;display:flex;flex-direction:column;background:#0d0d0d;overflow:hidden}._diffSummary_e9dmx_10{padding:8px 16px;background:#111;border-bottom:1px solid #2a2a2a;display:flex;gap:8px;align-items:center;flex-shrink:0}._addedBadge_e9dmx_20{padding:2px 8px;background:#73c99126;border:1px solid rgba(115,201,145,.3);border-radius:4px;font-size:11px;font-weight:600;color:#73c991;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace}._modifiedBadge_e9dmx_31{padding:2px 8px;background:#e2c08d26;border:1px solid rgba(226,192,141,.3);border-radius:4px;font-size:11px;font-weight:600;color:#e2c08d;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace}._deletedBadge_e9dmx_42{padding:2px 8px;background:#f14c4c26;border:1px solid rgba(241,76,76,.3);border-radius:4px;font-size:11px;font-weight:600;color:#f14c4c;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace}._codeContainer_e9dmx_53{flex:1;overflow:auto;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;font-size:13px;line-height:1.6}._codeLine_e9dmx_61{display:flex;position:relative;min-height:21px;transition:background .1s}._codeLine_e9dmx_61:hover{background:#ffffff08}._lineNumber_e9dmx_72{width:50px;flex-shrink:0;padding:0 12px 0 8px;text-align:right;color:#555;-webkit-user-select:none;user-select:none;font-size:12px}._lineContent_e9dmx_82{flex:1;padding-right:16px;color:#ccc;white-space:pre;overflow-x:auto}._lineNormal_e9dmx_90{background:transparent}._lineAdd_e9dmx_94{background:#73c9911a;border-left:3px solid #73c991}._lineAdd_e9dmx_94 ._lineNumber_e9dmx_72{color:#73c991;font-weight:600}._lineModify_e9dmx_104{background:#e2c08d1a;border-left:3px solid #e2c08d;position:relative}._lineModify_e9dmx_104 ._lineNumber_e9dmx_72{color:#e2c08d;font-weight:600}._lineDelete_e9dmx_115{background:#f14c4c1a;border-left:3px solid #f14c4c}._lineDelete_e9dmx_115 ._lineNumber_e9dmx_72{color:#f14c4c;font-weight:600}._lineDelete_e9dmx_115 ._lineContent_e9dmx_82{text-decoration:line-through;opacity:.8}._lineModify_e9dmx_104:hover ._oldContentTooltip_e9dmx_130{display:block}._oldContentTooltip_e9dmx_130{display:none;position:absolute;left:60px;top:100%;z-index:1000;background:#1a1a1a;border:1px solid #444;border-radius:4px;padding:8px 12px;max-width:600px;box-shadow:0 4px 12px #00000080;margin-top:4px}._tooltipLabel_e9dmx_149{font-size:10px;color:#888;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px}._tooltipContent_e9dmx_157{font-size:12px;color:#f14c4c;white-space:pre;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;text-decoration:line-through;opacity:.8}._gitDiffView_14i1p_1{flex:1;display:flex;flex-direction:column;background:#0d0d0d;overflow:hidden}._header_14i1p_9{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid #2a2a2a;background:#111;flex-shrink:0}._headerLeft_14i1p_19{display:flex;align-items:center;gap:12px;flex:1;min-width:0}._backBtn_14i1p_27{width:28px;height:28px;border:none;background:none;color:#888;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:4px;padding:0;flex-shrink:0;transition:all .15s}._backBtn_14i1p_27:hover{color:#ccc;background:#2a2a2a}._filePath_14i1p_48{font-size:13px;color:#ccc;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._diffBadge_14i1p_57{padding:2px 8px;background:#2a2a2a;border:1px solid #444;border-radius:4px;font-size:10px;font-weight:600;color:#e2c08d;letter-spacing:.5px;flex-shrink:0}._contentContainer_14i1p_69{flex:1;overflow:auto;position:relative}._loading_14i1p_75{display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:13px}._error_14i1p_84{display:flex;align-items:center;justify-content:center;height:100%;color:#ff6b6b;font-size:13px;padding:20px;text-align:center}._binaryNotice_14i1p_95{display:flex;align-items:center;justify-content:center;height:100%;color:#888;font-size:13px;font-style:italic;padding:20px;text-align:center}._largeFileWarning_14i1p_107{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;color:#e2c08d;font-size:13px;padding:20px;text-align:center;gap:8px}._fileSize_14i1p_120{color:#888;font-size:12px;margin:0}._centerEmpty_8tuwm_1{display:flex;align-items:center;justify-content:center;height:100%}._container_8tuwm_8{flex:1;overflow:auto;padding:16px 24px;display:flex;flex-direction:column;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}._sessionDividerText_8tuwm_18{font-size:11px;color:#555}._lastResponseLabel_8tuwm_23{font-size:11px}._splitContainer_8tuwm_27{display:flex;flex-direction:row;height:100%;overflow:hidden}._chatSection_8tuwm_34{display:flex;flex-direction:column;min-width:0;overflow:hidden}._vResizer_8tuwm_41{width:5px;background:#1a1a1a;cursor:col-resize;flex-shrink:0;border-left:1px solid #2a2a2a;border-right:1px solid #2a2a2a;transition:background .15s}._vResizer_8tuwm_41:hover{background:#2a2a2a}._snapLine_8tuwm_55{position:absolute;top:0;bottom:0;width:2px;background:transparent;border-left:2px dashed rgba(255,255,255,.1);pointer-events:none;z-index:1000;transition:all .15s}._snapLineActive_8tuwm_67{position:absolute;top:0;bottom:0;width:2px;background:transparent;border-left:2px dashed rgba(255,255,255,.5);pointer-events:none;z-index:1001}._snapLineLabel_8tuwm_78{position:absolute;top:50%;left:8px;transform:translateY(-50%);background:#ffffffe6;color:#000;padding:4px 8px;border-radius:4px;font-size:11px;font-weight:600;white-space:nowrap;font-family:SF Mono,Monaco,Cascadia Code,Roboto Mono,Consolas,Courier New,monospace;box-shadow:0 2px 8px #0000004d}._snapPreview_8tuwm_94{position:absolute;top:0;bottom:0;background:#ffffff1a;pointer-events:none;z-index:999}._vResizer_8tuwm_41:hover{background:#333}._chatInputBar_8tuwm_107{display:flex;align-items:flex-end;gap:8px;padding:10px 16px;background:#111;border-top:1px solid #2a2a2a;flex-shrink:0}._chatInputWrapper_8tuwm_117{flex:1;display:flex;flex-direction:column;background:#1a1a1a;border:1px solid #333;border-radius:12px;transition:border-color .2s;overflow:hidden}._chatInputWrapper_8tuwm_117:focus-within{border-color:#555}._chatTextareaWrap_8tuwm_132{position:relative;flex:1}._chatTextarea_8tuwm_132{width:100%;min-height:22px;max-height:120px;padding:10px 14px;background:transparent;color:#e0e0e0;border:none;outline:none;resize:none;font-size:14px;line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}._chatTextarea_8tuwm_132::placeholder{color:#555}._chatInputHint_8tuwm_156{font-size:11px;color:#444;padding:0 14px 6px;-webkit-user-select:none;user-select:none}._chatSendBtn_8tuwm_163{width:36px;height:36px;border-radius:10px;border:none;background:#4a9eff;color:#fff;cursor:pointer;display:flex;align-items:center;justify-content:center;flex-shrink:0;transition:background .15s,opacity .15s}._chatSendBtn_8tuwm_163:hover{background:#3a8eef}._chatSendBtn_8tuwm_163:disabled{opacity:.35;cursor:default}._chatSendBtn_8tuwm_163 svg{width:18px;height:18px}._messageListWrap_8tuwm_192{position:relative;flex:1;min-height:0;display:flex;flex-direction:column}._stickyBottomBtn_8tuwm_200{position:absolute;left:0;bottom:0;display:flex;flex-direction:column;align-items:center;gap:2px;padding:8px 18px;height:60px;justify-content:center;border-radius:0;border:none;background:none;color:#999;font-size:12px;cursor:pointer;transition:color .15s;z-index:10;box-shadow:none}._stickyBottomBtn_8tuwm_200 span{background:#00000080;padding:2px 10px;border-radius:10px}._stickyBottomBtn_8tuwm_200:hover{color:#fff;background:none}._ptyPromptBubble_8tuwm_233{margin:8px 0;padding:12px 16px;border-radius:12px;border:1px solid #3a3a3a;background:#161616;animation:_ptyPromptFadeIn_8tuwm_1 .25s ease-out}._ptyPromptResolved_8tuwm_242{opacity:.55}@keyframes _ptyPromptFadeIn_8tuwm_1{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}._ptyPromptQuestion_8tuwm_251{font-size:13px;color:#ccc;margin-bottom:10px;line-height:1.4}._ptyPromptOptions_8tuwm_258{display:flex;flex-wrap:wrap;gap:8px}._ptyPromptOption_8tuwm_258{padding:6px 14px;border-radius:18px;border:1px solid #3a3a3a;background:#1a1a1a;color:#bbb;font-size:12px;cursor:pointer;transition:background .15s,color .15s,border-color .15s;white-space:nowrap}._ptyPromptOption_8tuwm_258:hover{background:#2a2a2a;color:#eee;border-color:#555}._ptyPromptOptionPrimary_8tuwm_282{padding:6px 14px;border-radius:18px;border:1px solid #4a9eff;background:#4a9eff26;color:#4a9eff;font-size:12px;cursor:pointer;transition:background .15s,color .15s,border-color .15s;white-space:nowrap}._ptyPromptOptionPrimary_8tuwm_282:hover{background:#4a9eff40;color:#6ab4ff;border-color:#6ab4ff}._ptyPromptOptionChosen_8tuwm_300{padding:6px 14px;border-radius:18px;border:1px solid #4a9eff;background:#4a9eff33;color:#4a9eff;font-size:12px;cursor:default;white-space:nowrap}._ptyPromptOptionDimmed_8tuwm_311{padding:6px 14px;border-radius:18px;border:1px solid #2a2a2a;background:transparent;color:#444;font-size:12px;cursor:default;white-space:nowrap}._ghostText_8tuwm_322{position:absolute;top:0;left:0;right:0;padding:10px 14px;color:#444;font-size:14px;line-height:1.5;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;pointer-events:none;white-space:pre-wrap;overflow:hidden;max-height:120px}._suggestionChip_8tuwm_338{display:flex;align-items:center;gap:8px;padding:8px 14px;background:#1a1a1a;border-top:1px solid #2a2a2a;cursor:pointer;flex-shrink:0;transition:background .15s}._suggestionChip_8tuwm_338:hover{background:#222}._suggestionChipText_8tuwm_354{flex:1;color:#555;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._suggestionChipAction_8tuwm_363{color:#4a9eff;font-size:14px;flex-shrink:0}._navSidebar_8tuwm_369{width:40px;flex-shrink:0;background:#0d0d0d;border-right:1px solid #2a2a2a;display:flex;flex-direction:column;align-items:center;padding-top:8px;gap:4px}._navBtn_8tuwm_381{width:32px;height:32px;border:none;background:none;color:#666;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:6px;padding:0;transition:background .15s,color .15s}._navBtn_8tuwm_381:hover{color:#ccc;background:#1a1a1a}._navBtnActive_8tuwm_401{width:32px;height:32px;border:none;background:#4a9eff26;color:#4a9eff;cursor:pointer;display:flex;align-items:center;justify-content:center;border-radius:6px;padding:0;transition:background .15s,color .15s}._navBtnActive_8tuwm_401:hover{background:#4a9eff40;color:#6ab4ff}._resizer_yamj2_1{width:6px;cursor:col-resize;background:#1f1f1f;flex-shrink:0;transition:background .2s}._resizer_yamj2_1:hover{background:#3b82f6}._layout_t1dhs_1{height:100vh;overflow:hidden}._header_t1dhs_6{background:#111;border-bottom:1px solid #1f1f1f;padding:0 24px;height:60px;line-height:60px}._content_t1dhs_14{flex:1;overflow:hidden}._mainContainer_t1dhs_19{display:flex;height:100%}._leftPanel_t1dhs_24{flex-shrink:0;border-right:1px solid #1f1f1f;display:flex;flex-direction:column;background:#0a0a0a}._leftPanelHeader_t1dhs_32{padding:10px 16px;border-bottom:1px solid #1f1f1f;font-size:13px;color:#9ca3af;font-weight:500;display:flex;justify-content:space-between;align-items:center}._leftPanelCount_t1dhs_43{font-size:12px;color:#555;font-weight:400}._leftPanelBody_t1dhs_49{flex:1;overflow:hidden}._rightPanel_t1dhs_54{flex:1;overflow:hidden;background:#0d0d0d}._modalActions_t1dhs_60{margin-bottom:12px}._spinCenter_t1dhs_64{text-align:center;padding:40px}._emptyCenter_t1dhs_69{text-align:center;color:#999;padding:40px}._logCheckbox_t1dhs_75{margin-right:8px}._logListContainer_t1dhs_79{background:#0d0d0d;border-radius:8px;overflow:hidden}._logListItem_t1dhs_85{cursor:pointer;padding:8px 12px;border-bottom:1px solid #222}._logItemRow_t1dhs_91{display:flex;align-items:center;width:100%;justify-content:space-between;flex-wrap:nowrap;gap:12px}._logItemRow_t1dhs_91>span:first-child{display:flex;align-items:center;flex:1;min-width:0;overflow:hidden}._logFileName_t1dhs_108{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._logItemRow_t1dhs_91>span:last-child{display:flex;align-items:center;flex-shrink:0;gap:8px}._logFileIcon_t1dhs_121{margin-right:8px;color:#3b82f6;flex-shrink:0}._loadingOverlay_t1dhs_127{position:fixed;top:0;left:0;width:100vw;height:100vh;background:#000000bf;display:flex;align-items:center;justify-content:center;z-index:9999}._loadingText_t1dhs_140{color:#fff;font-size:16px;font-weight:700}._footer_t1dhs_146{height:18px;background:#000;display:flex;align-items:center;justify-content:flex-end;padding:0 12px;flex-shrink:0}._footerRight_t1dhs_156{display:flex;align-items:center;gap:6px;font-size:11px;color:#555}._footerText_t1dhs_164{color:#444;margin-right:2px}._footerLink_t1dhs_169{display:inline-flex;align-items:center;gap:3px;color:#555;text-decoration:none}._footerLink_t1dhs_169:hover{color:#888}._footerIcon_t1dhs_181{width:12px;height:12px}._footerDivider_t1dhs_186{color:#333}._footerText_t1dhs_164{color:#555}._guideContainer_t1dhs_194{display:flex;align-items:center;justify-content:center;height:100%;background:#0a0a0a}._guideContent_t1dhs_202{max-width:560px;padding:40px}._guideTitle_t1dhs_207{font-size:20px;font-weight:600;color:#e0e0e0;margin:0 0 28px}._guideStep_t1dhs_214{display:flex;gap:14px;margin-bottom:22px}._guideStepNum_t1dhs_220{flex-shrink:0;width:24px;height:24px;border-radius:50%;background:#1a1a2e;color:#7c8aff;font-size:13px;font-weight:600;display:flex;align-items:center;justify-content:center;margin-top:1px}._guideStepBody_t1dhs_235{flex:1;min-width:0}._guideText_t1dhs_240{color:#aaa;font-size:14px;line-height:1.6;margin:0 0 8px}._guideCode_t1dhs_247{display:block;background:#141414;border:1px solid #252525;border-radius:6px;padding:10px 14px;color:#8b9cf7;font-size:13px;line-height:1.5;word-break:break-all;white-space:pre-wrap}._mobileChatOverlay_t1dhs_260{position:absolute;top:0;right:0;bottom:0;left:0;transform:translate(100%);transition:transform .3s ease;z-index:100;background:#0a0a0a;display:flex;flex-direction:column;overflow:hidden}._mobileChatOverlayVisible_t1dhs_272{transform:translate(0)}._mobileChatInner_t1dhs_276{flex:1;min-height:0;display:flex;flex-direction:column;zoom:.6}
package/dist/index.html CHANGED
@@ -6,8 +6,8 @@
6
6
  <title>Claude Code Viewer</title>
7
7
  <link rel="icon" href="/favicon.ico?v=1">
8
8
  <link rel="shortcut icon" href="/favicon.ico?v=1">
9
- <script type="module" crossorigin src="/assets/index-CxuBY4Hs.js"></script>
10
- <link rel="stylesheet" crossorigin href="/assets/index-C9NseQNI.css">
9
+ <script type="module" crossorigin src="/assets/index-Cn5ba04w.js"></script>
10
+ <link rel="stylesheet" crossorigin href="/assets/index-S82X4YBV.css">
11
11
  </head>
12
12
  <body>
13
13
  <div id="root"></div>
package/interceptor.js CHANGED
@@ -143,7 +143,7 @@ const _initPromise = (async () => {
143
143
 
144
144
  export { LOG_FILE, _initPromise, _resumeState, _choicePromise, resolveResumeChoice, _projectName, _logDir };
145
145
 
146
- const MAX_LOG_SIZE = 500 * 1024 * 1024; // 500MB
146
+ const MAX_LOG_SIZE = 300 * 1024 * 1024; // 300MB
147
147
 
148
148
  function isPreflightEntry(entry) {
149
149
  if (entry.mainAgent || entry.isHeartbeat || entry.isCountTokens) return false;
@@ -484,7 +484,7 @@ export function setupInterceptor() {
484
484
  }
485
485
  } catch { }
486
486
 
487
- // 用户新指令边界:检查日志文件大小,超过 500MB 则切换新文件
487
+ // 用户新指令边界:检查日志文件大小,超过 300MB 则切换新文件
488
488
  if (requestEntry?.mainAgent) {
489
489
  checkAndRotateLogFile();
490
490
  // 仅 mainAgent 请求时缓存模型名,避免 SubAgent 覆盖
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-viewer",
3
- "version": "1.4.8",
3
+ "version": "1.4.10",
4
4
  "description": "Claude Code Logger visualization management tool",
5
5
  "license": "MIT",
6
6
  "main": "server.js",
@@ -62,6 +62,7 @@
62
62
  "@xterm/xterm": "^6.0.0",
63
63
  "antd": "^5.29.2",
64
64
  "diff": "^8.0.3",
65
+ "highlight.js": "^11.11.1",
65
66
  "marked": "^17.0.2",
66
67
  "qrcode.react": "^4.2.0",
67
68
  "react": "^18.3.1",
package/server.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createServer } from 'node:http';
2
2
  import { createConnection } from 'node:net';
3
3
  import { randomBytes } from 'node:crypto';
4
- import { readFileSync, writeFileSync, existsSync, watchFile, unwatchFile, statSync, readdirSync, renameSync, unlinkSync, openSync, readSync, closeSync } from 'node:fs';
4
+ import { readFileSync, writeFileSync, existsSync, watchFile, unwatchFile, statSync, readdirSync, renameSync, unlinkSync, openSync, readSync, closeSync, realpathSync } from 'node:fs';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import { dirname, join, extname } from 'node:path';
7
7
  import { homedir, userInfo, platform, networkInterfaces } from 'node:os';
@@ -523,6 +523,74 @@ function handleRequest(req, res) {
523
523
  return;
524
524
  }
525
525
 
526
+ // 文件浏览器 API(CLI 模式下项目目录浏览)
527
+ if (url === '/api/files' && method === 'GET') {
528
+ const reqPath = parsedUrl.searchParams.get('path') || '.';
529
+ // 安全校验:拒绝绝对路径和 .. 路径穿越
530
+ if (reqPath.startsWith('/') || reqPath.includes('..')) {
531
+ res.writeHead(400, { 'Content-Type': 'application/json' });
532
+ res.end(JSON.stringify({ error: 'Invalid path' }));
533
+ return;
534
+ }
535
+ const cwd = process.env.CCV_PROJECT_DIR || process.cwd();
536
+ const targetDir = join(cwd, reqPath);
537
+ try {
538
+ const entries = readdirSync(targetDir, { withFileTypes: true });
539
+ const HIDDEN = new Set(['node_modules', '.git', '.svn', '.hg', '.DS_Store', '__pycache__', '.next', '.nuxt', 'dist', '.cache', '.idea', '.vscode']);
540
+ const items = entries
541
+ .filter(e => !e.name.startsWith('.') && !HIDDEN.has(e.name))
542
+ .map(e => ({ name: e.name, type: e.isDirectory() ? 'directory' : 'file' }))
543
+ .sort((a, b) => {
544
+ if (a.type !== b.type) return a.type === 'directory' ? -1 : 1;
545
+ return a.name.localeCompare(b.name);
546
+ });
547
+ res.writeHead(200, { 'Content-Type': 'application/json' });
548
+ res.end(JSON.stringify(items));
549
+ } catch (err) {
550
+ res.writeHead(404, { 'Content-Type': 'application/json' });
551
+ res.end(JSON.stringify({ error: 'Directory not found' }));
552
+ }
553
+ return;
554
+ }
555
+
556
+ // 读取文件内容 API
557
+ if (url === '/api/file-content' && method === 'GET') {
558
+ const reqPath = parsedUrl.searchParams.get('path');
559
+ if (!reqPath || reqPath.startsWith('/') || reqPath.includes('..')) {
560
+ res.writeHead(400, { 'Content-Type': 'application/json' });
561
+ res.end(JSON.stringify({ error: 'Invalid path' }));
562
+ return;
563
+ }
564
+ const cwd = process.env.CCV_PROJECT_DIR || process.cwd();
565
+ const targetFile = join(cwd, reqPath);
566
+ try {
567
+ if (!existsSync(targetFile)) {
568
+ res.writeHead(404, { 'Content-Type': 'application/json' });
569
+ res.end(JSON.stringify({ error: `File not found: ${targetFile}` }));
570
+ return;
571
+ }
572
+ const stat = statSync(targetFile);
573
+ if (!stat.isFile()) {
574
+ res.writeHead(400, { 'Content-Type': 'application/json' });
575
+ res.end(JSON.stringify({ error: 'Not a file' }));
576
+ return;
577
+ }
578
+ // 限制文件大小 5MB
579
+ if (stat.size > 5 * 1024 * 1024) {
580
+ res.writeHead(413, { 'Content-Type': 'application/json' });
581
+ res.end(JSON.stringify({ error: 'File too large' }));
582
+ return;
583
+ }
584
+ const content = readFileSync(targetFile, 'utf-8');
585
+ res.writeHead(200, { 'Content-Type': 'application/json' });
586
+ res.end(JSON.stringify({ path: reqPath, content, size: stat.size }));
587
+ } catch (err) {
588
+ res.writeHead(500, { 'Content-Type': 'application/json' });
589
+ res.end(JSON.stringify({ error: `Cannot read file: ${err.message}` }));
590
+ }
591
+ return;
592
+ }
593
+
526
594
  // CLI 模式检测
527
595
  if (url === '/api/cli-mode' && method === 'GET') {
528
596
  res.writeHead(200, { 'Content-Type': 'application/json' });
@@ -530,6 +598,118 @@ function handleRequest(req, res) {
530
598
  return;
531
599
  }
532
600
 
601
+ // Git 状态
602
+ if (url === '/api/git-status' && method === 'GET') {
603
+ try {
604
+ const cwd = process.env.CCV_PROJECT_DIR || process.cwd();
605
+ const output = execSync('git status --porcelain', { cwd, encoding: 'utf-8', timeout: 5000 });
606
+ const lines = output.split('\n').filter(line => line.trim());
607
+ const changes = lines.map(line => {
608
+ const status = line.substring(0, 2).trim();
609
+ const file = line.substring(3).trim();
610
+ return { status, file };
611
+ });
612
+ res.writeHead(200, { 'Content-Type': 'application/json' });
613
+ res.end(JSON.stringify({ changes }));
614
+ } catch (err) {
615
+ res.writeHead(500, { 'Content-Type': 'application/json' });
616
+ res.end(JSON.stringify({ error: err.message, changes: [] }));
617
+ }
618
+ return;
619
+ }
620
+
621
+ // Git diff 数据获取
622
+ if (url.startsWith('/api/git-diff') && method === 'GET') {
623
+ try {
624
+ const cwd = process.env.CCV_PROJECT_DIR || process.cwd();
625
+ const filesParam = parsedUrl.searchParams.get('files');
626
+
627
+ if (!filesParam) {
628
+ res.writeHead(400, { 'Content-Type': 'application/json' });
629
+ res.end(JSON.stringify({ error: 'Missing files parameter' }));
630
+ return;
631
+ }
632
+
633
+ const files = filesParam.split(',').map(f => f.trim()).filter(Boolean);
634
+ const diffs = [];
635
+
636
+ for (const file of files) {
637
+ // 安全检查:防止路径穿越
638
+ if (file.includes('..') || file.startsWith('/')) continue;
639
+
640
+ try {
641
+ const statusOutput = execSync(`git status --porcelain "${file}"`, { cwd, encoding: 'utf-8', timeout: 3000 });
642
+ if (!statusOutput.trim()) continue;
643
+
644
+ const status = statusOutput.substring(0, 2).trim();
645
+ const is_new = status === 'A' || status === '??';
646
+ const is_deleted = status === 'D';
647
+
648
+ // 检查是否为二进制文件
649
+ let is_binary = false;
650
+ try {
651
+ const diffCheck = execSync(`git diff --numstat HEAD "${file}"`, { cwd, encoding: 'utf-8', timeout: 3000 });
652
+ if (diffCheck.includes('-\t-\t')) {
653
+ is_binary = true;
654
+ }
655
+ } catch {}
656
+
657
+ let old_content = '';
658
+ let new_content = '';
659
+
660
+ if (!is_binary) {
661
+ // 获取旧内容(HEAD 版本)
662
+ if (!is_new) {
663
+ try {
664
+ old_content = execSync(`git show HEAD:"${file}"`, { cwd, encoding: 'utf-8', timeout: 5000, maxBuffer: 5 * 1024 * 1024 });
665
+ } catch {
666
+ old_content = '';
667
+ }
668
+ }
669
+
670
+ // 获取新内容(工作区版本)
671
+ if (!is_deleted) {
672
+ try {
673
+ const filePath = join(cwd, file);
674
+ if (existsSync(filePath)) {
675
+ const stat = statSync(filePath);
676
+ if (stat.size > 5 * 1024 * 1024) {
677
+ // 文件过大
678
+ diffs.push({ file, status, is_large: true, size: stat.size });
679
+ continue;
680
+ }
681
+ new_content = readFileSync(filePath, 'utf-8');
682
+ }
683
+ } catch {
684
+ new_content = '';
685
+ }
686
+ }
687
+ }
688
+
689
+ diffs.push({
690
+ file,
691
+ status,
692
+ old_content,
693
+ new_content,
694
+ is_binary,
695
+ is_new,
696
+ is_deleted
697
+ });
698
+ } catch (err) {
699
+ // 跳过无法处理的文件
700
+ continue;
701
+ }
702
+ }
703
+
704
+ res.writeHead(200, { 'Content-Type': 'application/json' });
705
+ res.end(JSON.stringify({ diffs }));
706
+ } catch (err) {
707
+ res.writeHead(500, { 'Content-Type': 'application/json' });
708
+ res.end(JSON.stringify({ error: err.message, diffs: [] }));
709
+ }
710
+ return;
711
+ }
712
+
533
713
  // 返回局域网访问地址
534
714
  if (url === '/api/local-url' && method === 'GET') {
535
715
  const nets = networkInterfaces();
@@ -592,14 +772,21 @@ function handleRequest(req, res) {
592
772
  }
593
773
 
594
774
  // 读取指定本地日志文件(支持 project/file 路径)
595
- if (url.startsWith('/api/local-log?') && method === 'GET') {
596
- const params = new URLSearchParams(url.split('?')[1]);
597
- const file = params.get('file');
775
+ if (url === '/api/local-log' && method === 'GET') {
776
+ const file = parsedUrl.searchParams.get('file');
598
777
  if (!file || file.includes('..')) {
599
778
  res.writeHead(400, { 'Content-Type': 'application/json' });
600
779
  res.end(JSON.stringify({ error: 'Invalid file name' }));
601
780
  return;
602
781
  }
782
+
783
+ // 验证文件类型:只允许 .jsonl 文件
784
+ if (!file.endsWith('.jsonl')) {
785
+ res.writeHead(400, { 'Content-Type': 'application/json' });
786
+ res.end(JSON.stringify({ error: 'Invalid file type. Only .jsonl files are allowed.' }));
787
+ return;
788
+ }
789
+
603
790
  const filePath = join(LOG_DIR, file);
604
791
  try {
605
792
  if (!existsSync(filePath)) {
@@ -607,6 +794,16 @@ function handleRequest(req, res) {
607
794
  res.end(JSON.stringify({ error: 'File not found' }));
608
795
  return;
609
796
  }
797
+
798
+ // 验证文件确实在 LOG_DIR 内(防止路径穿越)
799
+ const realPath = realpathSync(filePath);
800
+ const realLogDir = realpathSync(LOG_DIR);
801
+ if (!realPath.startsWith(realLogDir)) {
802
+ res.writeHead(403, { 'Content-Type': 'application/json' });
803
+ res.end(JSON.stringify({ error: 'Access denied' }));
804
+ return;
805
+ }
806
+
610
807
  const content = readFileSync(filePath, 'utf-8');
611
808
  const entries = content.split('\n---\n').filter(line => line.trim()).map(entry => {
612
809
  try { return JSON.parse(entry); } catch { return null; }
@@ -672,10 +869,9 @@ function handleRequest(req, res) {
672
869
  }
673
870
 
674
871
  // GET /api/concept?lang=zh&doc=Tool-Bash
675
- if (method === 'GET' && url.startsWith('/api/concept')) {
676
- const conceptParams = new URL(url, 'http://localhost').searchParams;
677
- const lang = conceptParams.get('lang') || 'zh';
678
- const doc = conceptParams.get('doc') || '';
872
+ if (method === 'GET' && url === '/api/concept') {
873
+ const lang = parsedUrl.searchParams.get('lang') || 'zh';
874
+ const doc = parsedUrl.searchParams.get('doc') || '';
679
875
  // 安全校验:只允许字母、数字、连字符
680
876
  if (!/^[a-zA-Z0-9-]+$/.test(doc) || !/^[a-z]{2}(-[a-zA-Z]{2,})?$/.test(lang)) {
681
877
  res.writeHead(400, { 'Content-Type': 'application/json' });
@@ -758,8 +954,8 @@ export async function startViewer() {
758
954
  currentServer.listen(port, HOST, () => {
759
955
  server = currentServer;
760
956
  actualPort = port;
761
- const url = `http://${HOST}:${port}`;
762
- console.error(t('server.started', { host: HOST, port }));
957
+ const url = `http://127.0.0.1:${port}`;
958
+ console.error(t('server.started', { host: '127.0.0.1', port }));
763
959
  // v2.0.69 之前的版本会清空控制台,自动打开浏览器确保用户能看到界面
764
960
  try {
765
961
  const ccPkgPath = join(__dirname, '..', '@anthropic-ai', 'claude-code', 'package.json');