cc-viewer 1.4.9 → 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.
@@ -38,4 +38,4 @@ body{margin:0;background-color:#0d0d0d}*{scrollbar-width:thin;scrollbar-color:#3
38
38
 
39
39
  Outdated base version: https://github.com/primer/github-syntax-dark
40
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_1jjqw_1{display:flex;align-items:center;justify-content:center;height:100%}._container_1jjqw_8{flex:1;overflow:auto;padding:16px 24px;display:flex;flex-direction:column;-webkit-overflow-scrolling:touch;overscroll-behavior:contain}._sessionDividerText_1jjqw_18{font-size:11px;color:#555}._lastResponseLabel_1jjqw_23{font-size:11px}._splitContainer_1jjqw_27{display:flex;flex-direction:row;height:100%;overflow:hidden}._chatSection_1jjqw_34{display:flex;flex-direction:column;min-width:0;overflow:hidden}._vResizer_1jjqw_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_1jjqw_41:hover{background:#333}._chatInputBar_1jjqw_55{display:flex;align-items:flex-end;gap:8px;padding:10px 16px;background:#111;border-top:1px solid #2a2a2a;flex-shrink:0}._chatInputWrapper_1jjqw_65{flex:1;display:flex;flex-direction:column;background:#1a1a1a;border:1px solid #333;border-radius:12px;transition:border-color .2s;overflow:hidden}._chatInputWrapper_1jjqw_65:focus-within{border-color:#555}._chatTextareaWrap_1jjqw_80{position:relative;flex:1}._chatTextarea_1jjqw_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_1jjqw_80::placeholder{color:#555}._chatInputHint_1jjqw_104{font-size:11px;color:#444;padding:0 14px 6px;-webkit-user-select:none;user-select:none}._chatSendBtn_1jjqw_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_1jjqw_111:hover{background:#3a8eef}._chatSendBtn_1jjqw_111:disabled{opacity:.35;cursor:default}._chatSendBtn_1jjqw_111 svg{width:18px;height:18px}._messageListWrap_1jjqw_140{position:relative;flex:1;min-height:0;display:flex;flex-direction:column}._stickyBottomBtn_1jjqw_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_1jjqw_148 span{background:#00000080;padding:2px 10px;border-radius:10px}._stickyBottomBtn_1jjqw_148:hover{color:#fff;background:none}._ptyPromptBubble_1jjqw_181{margin:8px 0;padding:12px 16px;border-radius:12px;border:1px solid #3a3a3a;background:#161616;animation:_ptyPromptFadeIn_1jjqw_1 .25s ease-out}._ptyPromptResolved_1jjqw_190{opacity:.55}@keyframes _ptyPromptFadeIn_1jjqw_1{0%{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}._ptyPromptQuestion_1jjqw_199{font-size:13px;color:#ccc;margin-bottom:10px;line-height:1.4}._ptyPromptOptions_1jjqw_206{display:flex;flex-wrap:wrap;gap:8px}._ptyPromptOption_1jjqw_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_1jjqw_206:hover{background:#2a2a2a;color:#eee;border-color:#555}._ptyPromptOptionPrimary_1jjqw_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_1jjqw_230:hover{background:#4a9eff40;color:#6ab4ff;border-color:#6ab4ff}._ptyPromptOptionChosen_1jjqw_248{padding:6px 14px;border-radius:18px;border:1px solid #4a9eff;background:#4a9eff33;color:#4a9eff;font-size:12px;cursor:default;white-space:nowrap}._ptyPromptOptionDimmed_1jjqw_259{padding:6px 14px;border-radius:18px;border:1px solid #2a2a2a;background:transparent;color:#444;font-size:12px;cursor:default;white-space:nowrap}._ghostText_1jjqw_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_1jjqw_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_1jjqw_286:hover{background:#222}._suggestionChipText_1jjqw_302{flex:1;color:#555;font-size:13px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}._suggestionChipAction_1jjqw_311{color:#4a9eff;font-size:14px;flex-shrink:0}._navSidebar_1jjqw_317{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_1jjqw_329{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_1jjqw_329:hover{color:#ccc;background:#1a1a1a}._navBtnActive_1jjqw_349{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_1jjqw_349: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}
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-BtUV1IH_.js"></script>
10
- <link rel="stylesheet" crossorigin href="/assets/index-Cplbs2JB.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cc-viewer",
3
- "version": "1.4.9",
3
+ "version": "1.4.10",
4
4
  "description": "Claude Code Logger visualization management tool",
5
5
  "license": "MIT",
6
6
  "main": "server.js",
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';
@@ -772,14 +772,21 @@ function handleRequest(req, res) {
772
772
  }
773
773
 
774
774
  // 读取指定本地日志文件(支持 project/file 路径)
775
- if (url.startsWith('/api/local-log?') && method === 'GET') {
776
- const params = new URLSearchParams(url.split('?')[1]);
777
- const file = params.get('file');
775
+ if (url === '/api/local-log' && method === 'GET') {
776
+ const file = parsedUrl.searchParams.get('file');
778
777
  if (!file || file.includes('..')) {
779
778
  res.writeHead(400, { 'Content-Type': 'application/json' });
780
779
  res.end(JSON.stringify({ error: 'Invalid file name' }));
781
780
  return;
782
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
+
783
790
  const filePath = join(LOG_DIR, file);
784
791
  try {
785
792
  if (!existsSync(filePath)) {
@@ -787,6 +794,16 @@ function handleRequest(req, res) {
787
794
  res.end(JSON.stringify({ error: 'File not found' }));
788
795
  return;
789
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
+
790
807
  const content = readFileSync(filePath, 'utf-8');
791
808
  const entries = content.split('\n---\n').filter(line => line.trim()).map(entry => {
792
809
  try { return JSON.parse(entry); } catch { return null; }
@@ -852,10 +869,9 @@ function handleRequest(req, res) {
852
869
  }
853
870
 
854
871
  // GET /api/concept?lang=zh&doc=Tool-Bash
855
- if (method === 'GET' && url.startsWith('/api/concept')) {
856
- const conceptParams = new URL(url, 'http://localhost').searchParams;
857
- const lang = conceptParams.get('lang') || 'zh';
858
- 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') || '';
859
875
  // 安全校验:只允许字母、数字、连字符
860
876
  if (!/^[a-zA-Z0-9-]+$/.test(doc) || !/^[a-z]{2}(-[a-zA-Z]{2,})?$/.test(lang)) {
861
877
  res.writeHead(400, { 'Content-Type': 'application/json' });