@caoruhua/open-claude-remote 1.0.5 → 1.0.7

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 @@
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}.markdown-body{-webkit-overflow-scrolling:touch}.markdown-body pre{overflow-x:auto;max-width:100%}.markdown-body table{display:block;overflow-x:auto;max-width:100%}@media(max-width:768px){.toc-fab{display:flex!important}.toc-drawer{display:block!important}.toc-sidebar{display:none!important}}@media(min-width:769px){.toc-fab,.toc-drawer{display:none!important}.toc-sidebar{display:block!important}.viewer-content{margin-right:260px}}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif;font-size:1rem;line-height:1.6;color:var(--text-primary);word-wrap:break-word}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.25;scroll-margin-top:4rem}.markdown-body h1{font-size:1.75rem;padding-bottom:.3em;border-bottom:1px solid var(--border-color)}.markdown-body h2{font-size:1.5rem;padding-bottom:.3em;border-bottom:1px solid var(--border-color)}.markdown-body h3{font-size:1.25rem}.markdown-body h4{font-size:1rem}.markdown-body h5{font-size:.875rem}.markdown-body h6{font-size:.85em;color:var(--text-secondary)}.markdown-body p{margin:1em 0}.markdown-body a{color:var(--accent-color);text-decoration:none}.markdown-body a:hover{text-decoration:underline}.markdown-body ul,.markdown-body ol{margin:1em 0;padding-left:2em}.markdown-body li{margin:.25em 0}.markdown-body li+li{margin-top:.25em}.markdown-body blockquote{margin:1em 0;padding:.5em 1em;border-left:4px solid var(--border-color);background:var(--bg-secondary);color:var(--text-secondary)}.markdown-body blockquote p{margin:0}.markdown-body code{padding:.2em .4em;background:var(--bg-secondary);border-radius:.25rem;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.875em}.markdown-body pre{margin:1em 0;padding:1em;background:var(--bg-secondary);border-radius:.5rem;overflow-x:auto}.markdown-body pre code{padding:0;background:none;font-size:.875rem;line-height:1.45}.markdown-body table{margin:1em 0;border-collapse:collapse;width:100%;overflow:auto;display:block}.markdown-body table th,.markdown-body table td{padding:.5em .75em;border:1px solid var(--border-color)}.markdown-body table th{font-weight:600;background:var(--bg-secondary)}.markdown-body table tr:nth-child(2n){background:var(--bg-secondary)}.hljs{background:transparent!important;padding:0!important}.markdown-body input[type=checkbox]{margin-right:.5em;vertical-align:middle}.markdown-body img{max-width:100%;height:auto;border-radius:.5rem}.markdown-body hr{margin:2em 0;border:none;border-top:1px solid var(--border-color)}.markdown-body del{color:var(--text-secondary)}:root{color-scheme:dark;--bg-primary: #0d1117;--bg-secondary: #161b22;--bg-tertiary: #21262d;--bg-overlay: rgba(0, 0, 0, .6);--text-primary: #e6edf3;--text-secondary: #8b949e;--text-muted: #484f58;--border-color: #30363d;--status-idle: #3fb950;--status-running: #58a6ff;--status-waiting: #d29922;--status-error: #f85149;--status-disconnected: #8b949e;--approve-bg: #238636;--approve-hover: #2ea043;--reject-bg: #da3633;--reject-hover: #f85149;--safe-top: env(safe-area-inset-top, 0px);--safe-bottom: env(safe-area-inset-bottom, 0px);--safe-left: env(safe-area-inset-left, 0px);--safe-right: env(safe-area-inset-right, 0px);--statusbar-height: 44px;--inputbar-height: 56px;--min-touch-target: 44px;--keybar-height: 48px;--breakpoint-tablet: 768px;--breakpoint-desktop: 1024px;--app-height: 100dvh;--content-inline-padding: 12px;--content-inline-padding-tablet: 16px;--bottom-interactive-inset: var(--safe-bottom);--font-mono: "JetBrains Mono", "Menlo", "Monaco", "Courier New", monospace;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:var(--app-height);width:100%;overflow:hidden;background:var(--bg-primary);color:var(--text-primary);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overscroll-behavior:none}@supports not (height: 100dvh){:root{--app-height: 100vh}}body{padding-left:var(--safe-left);padding-right:var(--safe-right)}@media(min-width:768px){:root{--content-inline-padding: var(--content-inline-padding-tablet)}}button,input,label,nav{-webkit-user-select:none;user-select:none}input{font-family:inherit;font-size:16px}button{cursor:pointer;border:none;background:none;font-family:inherit;font-size:inherit;color:inherit}.app-toast{position:fixed;left:50%;bottom:calc(16px + var(--safe-bottom));transform:translate(-50%);z-index:2000;padding:8px 12px;border-radius:8px;background:#111827eb;color:#fff;font-size:13px;line-height:1.4;white-space:nowrap}.app-toast-top{top:calc(var(--safe-top) + 8px);bottom:auto}.focus-ring:focus-visible{outline:none;box-shadow:0 0 0 2px var(--bg-primary),0 0 0 4px #58a6ff}.perm-btn{touch-action:manipulation;-webkit-tap-highlight-color:transparent;transition:opacity .1s,background .1s}.perm-btn:hover{opacity:.85}.perm-btn:active{opacity:.7}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}input:focus-visible,textarea:focus-visible{outline:none;box-shadow:0 0 0 2px var(--bg-primary),0 0 0 4px #58a6ff}button{touch-action:manipulation;-webkit-tap-highlight-color:transparent}.xterm-helper-textarea{pointer-events:none;-webkit-user-select:none;user-select:none}.xterm{height:100%;width:100%}@keyframes fadeInOut{0%{opacity:0;transform:translate(-50%) translateY(10px)}10%{opacity:1;transform:translate(-50%) translateY(0)}90%{opacity:1;transform:translate(-50%) translateY(0)}to{opacity:0;transform:translate(-50%) translateY(-10px)}}
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}.markdown-body{-webkit-overflow-scrolling:touch}.markdown-body pre{overflow-x:auto;max-width:100%}.markdown-body table{display:block;overflow-x:auto;max-width:100%}@media(max-width:768px){.toc-fab{display:flex!important}.toc-drawer{display:block!important}.toc-sidebar{display:none!important}}@media(min-width:769px){.toc-fab,.toc-drawer{display:none!important}.toc-sidebar{display:block!important}.viewer-content{margin-right:260px}}.markdown-body{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Noto Sans,Helvetica,Arial,sans-serif;font-size:1rem;line-height:1.6;color:var(--text-primary);word-wrap:break-word}.markdown-body h1,.markdown-body h2,.markdown-body h3,.markdown-body h4,.markdown-body h5,.markdown-body h6{margin-top:1.5em;margin-bottom:.5em;font-weight:600;line-height:1.25;scroll-margin-top:4rem;text-wrap:pretty}.markdown-body h1{font-size:1.75rem;padding-bottom:.3em;border-bottom:1px solid var(--border-color)}.markdown-body h2{font-size:1.5rem;padding-bottom:.3em;border-bottom:1px solid var(--border-color)}.markdown-body h3{font-size:1.25rem}.markdown-body h4{font-size:1rem}.markdown-body h5{font-size:.875rem}.markdown-body h6{font-size:.85em;color:var(--text-secondary)}.markdown-body p{margin:1em 0}.markdown-body a{color:var(--accent-color);text-decoration:none;min-height:44px;display:inline-flex;align-items:center}.markdown-body a:hover{text-decoration:underline}.markdown-body ul,.markdown-body ol{margin:1em 0;padding-left:2em}.markdown-body li{margin:.25em 0}.markdown-body li+li{margin-top:.25em}.markdown-body blockquote{margin:1em 0;padding:1em 1.25em;border-left:4px solid var(--accent-color);background:var(--bg-secondary);color:var(--text-secondary);border-radius:0 .5rem .5rem 0}.markdown-body blockquote p{margin:0}.markdown-body blockquote p+p{margin-top:.5em}.markdown-body code{padding:.2em .4em;background:var(--bg-secondary);border-radius:.25rem;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:.875em}.markdown-body pre{margin:1em 0;padding:1em;background:var(--bg-secondary);border-radius:.5rem;overflow-x:auto;-webkit-overflow-scrolling:touch}.markdown-body pre code{padding:0;background:none;font-size:.875rem;line-height:1.45}.markdown-body table{margin:1em 0;border-collapse:collapse;width:100%;overflow:auto;display:block;-webkit-overflow-scrolling:touch}.markdown-body table th,.markdown-body table td{padding:.5em .75em;border:1px solid var(--border-color)}.markdown-body table th{font-weight:600;background:var(--bg-secondary)}.markdown-body table tr:nth-child(2n){background:var(--bg-secondary)}.hljs{background:transparent!important;padding:0!important}.markdown-body input[type=checkbox]{margin-right:.5em;vertical-align:middle;width:18px;height:18px;min-width:18px;min-height:18px;cursor:pointer}.markdown-body img{max-width:100%;height:auto;border-radius:.5rem;box-shadow:0 2px 8px #0000001a;transition:opacity .2s ease,box-shadow .2s ease}.markdown-body img:hover{box-shadow:0 4px 16px #00000026}.markdown-body img[src=""]{display:none}.markdown-body hr{margin:2em 0;border:none;border-top:1px solid var(--border-color)}.markdown-body del{color:var(--text-secondary)}@media(max-width:768px){.markdown-body{font-size:16px;line-height:1.75}.markdown-body p{margin:1.25em 0}.markdown-body h1{font-size:1.5rem}.markdown-body h2{font-size:1.375rem}.markdown-body h3{font-size:1.125rem}.markdown-body ul,.markdown-body ol{padding-left:1.5em}.markdown-body pre{padding:.875em;font-size:.8125rem}.markdown-body code{font-size:.8125em}.markdown-body blockquote{padding:.875em 1em}.markdown-body table{font-size:.875rem}.markdown-body table th,.markdown-body table td{padding:.375em .5em}}@media(prefers-reduced-motion:reduce){.markdown-body img,.markdown-body a,.markdown-body *{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}.image-preview-trigger{cursor:pointer}@supports (padding-top: env(safe-area-inset-top)){.markdown-body{padding-left:env(safe-area-inset-left);padding-right:env(safe-area-inset-right)}}.markdown-body span[style*="color:"],.markdown-body font[color]{display:inline}.markdown-body sub,.markdown-body sup{font-size:.75em;line-height:0;position:relative;vertical-align:baseline}.markdown-body sup{top:-.5em}.markdown-body sub{bottom:-.25em}.markdown-body mark{background-color:#ffd7004d;padding:.125em .25em;border-radius:.125rem}.markdown-body br{display:block;content:"";margin-top:.5em}:root{color-scheme:dark;--bg-primary: #0d1117;--bg-secondary: #161b22;--bg-tertiary: #21262d;--bg-overlay: rgba(0, 0, 0, .6);--text-primary: #e6edf3;--text-secondary: #8b949e;--text-muted: #484f58;--border-color: #30363d;--status-idle: #3fb950;--status-running: #58a6ff;--status-waiting: #d29922;--status-error: #f85149;--status-disconnected: #8b949e;--approve-bg: #238636;--approve-hover: #2ea043;--reject-bg: #da3633;--reject-hover: #f85149;--safe-top: env(safe-area-inset-top, 0px);--safe-bottom: env(safe-area-inset-bottom, 0px);--safe-left: env(safe-area-inset-left, 0px);--safe-right: env(safe-area-inset-right, 0px);--statusbar-height: 44px;--inputbar-height: 56px;--min-touch-target: 44px;--keybar-height: 48px;--breakpoint-tablet: 768px;--breakpoint-desktop: 1024px;--app-height: 100dvh;--content-inline-padding: 12px;--content-inline-padding-tablet: 16px;--bottom-interactive-inset: var(--safe-bottom);--font-mono: "JetBrains Mono", "Menlo", "Monaco", "Courier New", monospace;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:var(--app-height);width:100%;overflow:hidden;background:var(--bg-primary);color:var(--text-primary);font-family:var(--font-sans);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;overscroll-behavior:none}@supports not (height: 100dvh){:root{--app-height: 100vh}}body{padding-left:var(--safe-left);padding-right:var(--safe-right)}@media(min-width:768px){:root{--content-inline-padding: var(--content-inline-padding-tablet)}}button,input,label,nav{-webkit-user-select:none;user-select:none}input{font-family:inherit;font-size:16px}button{cursor:pointer;border:none;background:none;font-family:inherit;font-size:inherit;color:inherit}.app-toast{position:fixed;left:50%;bottom:calc(16px + var(--safe-bottom));transform:translate(-50%);z-index:2000;padding:8px 12px;border-radius:8px;background:#111827eb;color:#fff;font-size:13px;line-height:1.4;white-space:nowrap}.app-toast-top{top:calc(var(--safe-top) + 8px);bottom:auto}.focus-ring:focus-visible{outline:none;box-shadow:0 0 0 2px var(--bg-primary),0 0 0 4px #58a6ff}.perm-btn{touch-action:manipulation;-webkit-tap-highlight-color:transparent;transition:opacity .1s,background .1s}.perm-btn:hover{opacity:.85}.perm-btn:active{opacity:.7}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}}input:focus-visible,textarea:focus-visible{outline:none;box-shadow:0 0 0 2px var(--bg-primary),0 0 0 4px #58a6ff}button{touch-action:manipulation;-webkit-tap-highlight-color:transparent}.xterm-helper-textarea{pointer-events:none;-webkit-user-select:none;user-select:none}.xterm{height:100%;width:100%}@keyframes fadeInOut{0%{opacity:0;transform:translate(-50%) translateY(10px)}10%{opacity:1;transform:translate(-50%) translateY(0)}90%{opacity:1;transform:translate(-50%) translateY(0)}to{opacity:0;transform:translate(-50%) translateY(-10px)}}
@@ -6,8 +6,8 @@
6
6
  <meta name="apple-mobile-web-app-capable" content="yes" />
7
7
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
8
8
  <title>Claude Code Remote</title>
9
- <script type="module" crossorigin src="/assets/index-CvWXztaS.js"></script>
10
- <link rel="stylesheet" crossorigin href="/assets/index-6CW6J4Mw.css">
9
+ <script type="module" crossorigin src="/assets/index-CVRtrLyp.js"></script>
10
+ <link rel="stylesheet" crossorigin href="/assets/index-UXAwH56Q.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": "@caoruhua/open-claude-remote",
3
- "version": "1.0.5",
3
+ "version": "1.0.7",
4
4
  "description": "Remote control proxy for Claude Code CLI - control your PC terminal from mobile browser",
5
5
  "keywords": [
6
6
  "claude",
@@ -88,6 +88,7 @@
88
88
  "react-markdown": "^10.1.0",
89
89
  "react-router-dom": "^7.5.2",
90
90
  "rehype-highlight": "^7.0.2",
91
+ "rehype-raw": "^7.0.0",
91
92
  "remark-gfm": "^4.0.1",
92
93
  "tsc-alias": "^1.8.16",
93
94
  "tsx": "^4.21.0",
@@ -1,83 +0,0 @@
1
- /**
2
- * Markdown 文件路径检测结果
3
- */
4
- export interface DetectedPath {
5
- /** 原始匹配到的路径字符串 */
6
- raw: string;
7
- /** 解析后的绝对路径 */
8
- absolute: string;
9
- /** 相对于 cwd 的相对路径(如果适用) */
10
- relative?: string;
11
- }
12
- /**
13
- * PathDetector: PTY 输出中的 Markdown 文件路径检测器
14
- *
15
- * 匹配规则:
16
- * 1. 绝对路径:以 / 开头,如 `/Users/tom/project/README.md`
17
- * 2. 相对路径:以 ./ 开头,如 `./docs/guide.md`
18
- * 3. 仅匹配 .md 或 .markdown 扩展名
19
- *
20
- * 使用方式:
21
- * ```ts
22
- * const detector = new PathDetector('/Users/tom/project');
23
- * const paths = detector.detect('See ./docs/guide.md for details');
24
- * // paths = [{ raw: './docs/guide.md', absolute: '/Users/tom/project/docs/guide.md', relative: './docs/guide.md' }]
25
- * ```
26
- */
27
- export declare class PathDetector {
28
- private readonly cwd;
29
- /**
30
- * 匹配 ANSI 转义序列的正则表达式
31
- * 用于去除终端输出中的颜色/样式代码
32
- */
33
- private static readonly ANSI_ESCAPE_REGEX;
34
- /**
35
- * 匹配 Markdown 文件路径的正则表达式
36
- *
37
- * 解释:
38
- * - (?:^|[\s"'`(|\[]) 前导边界:行首、空白、引号、反引号、括号、方括号
39
- * - ( 开始捕获组
40
- * - \/? 可选开头的斜杠(相对路径可能不包含)
41
- * - (?:\.\/|\.\.\/)? 可选的相对路径前缀 ./ 或 ../
42
- * - [^\s"'`|)\]]+? 非贪婪匹配路径字符(排除空白、引号、括号等)
43
- * - \.(?:md|markdown) 匹配 .md 或 .markdown 扩展名
44
- * - ) 结束捕获组
45
- *
46
- * 注意:此正则不匹配绝对路径(以 / 开头的路径),需单独处理
47
- */
48
- private static readonly RELATIVE_MD_PATH_REGEX;
49
- /**
50
- * 匹配绝对路径的正则表达式
51
- * 以 / 开头,匹配 .md 或 .markdown 文件
52
- */
53
- private static readonly ABSOLUTE_MD_PATH_REGEX;
54
- constructor(cwd: string);
55
- /**
56
- * 去除文本中的 ANSI 转义序列
57
- */
58
- private static stripAnsi;
59
- /**
60
- * 从文本中检测 Markdown 文件路径
61
- *
62
- * @param text - PTY 输出的文本(可能包含 ANSI 转义序列)
63
- * @returns 检测到的路径数组(去重后)
64
- */
65
- detect(text: string): DetectedPath[];
66
- /**
67
- * 检查路径是否在允许的目录范围内
68
- *
69
- * @param absolutePath - 要检查的绝对路径
70
- * @param allowedPaths - 允许的目录列表
71
- * @returns 是否允许访问
72
- */
73
- static isPathAllowed(absolutePath: string, allowedPaths: string[]): boolean;
74
- /**
75
- * 规范化路径,返回绝对路径
76
- *
77
- * @param path - 原始路径
78
- * @param baseDir - 基础目录(用于相对路径解析)
79
- * @returns 解析后的绝对路径,解析失败返回 null
80
- */
81
- static normalizePath(path: string, baseDir: string): string | null;
82
- }
83
- //# sourceMappingURL=path-detector.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"path-detector.d.ts","sourceRoot":"","sources":["../../../../backend/src/pty/path-detector.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,kBAAkB;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,eAAe;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;GAcG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;IAE7B;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,iBAAiB,CAA4B;IAErE;;;;;;;;;;;;;OAaG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAA0E;IAExH;;;OAGG;IACH,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAA4D;gBAE9F,GAAG,EAAE,MAAM;IAIvB;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,SAAS;IAIxB;;;;;OAKG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,EAAE;IAqEpC;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,GAAG,OAAO;IAa3E;;;;;;OAMG;IACH,MAAM,CAAC,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;CAUnE"}
@@ -1,163 +0,0 @@
1
- import { resolve, relative, isAbsolute } from 'node:path';
2
- import { logger } from '../logger/logger.js';
3
- /**
4
- * PathDetector: PTY 输出中的 Markdown 文件路径检测器
5
- *
6
- * 匹配规则:
7
- * 1. 绝对路径:以 / 开头,如 `/Users/tom/project/README.md`
8
- * 2. 相对路径:以 ./ 开头,如 `./docs/guide.md`
9
- * 3. 仅匹配 .md 或 .markdown 扩展名
10
- *
11
- * 使用方式:
12
- * ```ts
13
- * const detector = new PathDetector('/Users/tom/project');
14
- * const paths = detector.detect('See ./docs/guide.md for details');
15
- * // paths = [{ raw: './docs/guide.md', absolute: '/Users/tom/project/docs/guide.md', relative: './docs/guide.md' }]
16
- * ```
17
- */
18
- export class PathDetector {
19
- cwd;
20
- /**
21
- * 匹配 ANSI 转义序列的正则表达式
22
- * 用于去除终端输出中的颜色/样式代码
23
- */
24
- static ANSI_ESCAPE_REGEX = /\x1b\[[0-9;]*[a-zA-Z]/g;
25
- /**
26
- * 匹配 Markdown 文件路径的正则表达式
27
- *
28
- * 解释:
29
- * - (?:^|[\s"'`(|\[]) 前导边界:行首、空白、引号、反引号、括号、方括号
30
- * - ( 开始捕获组
31
- * - \/? 可选开头的斜杠(相对路径可能不包含)
32
- * - (?:\.\/|\.\.\/)? 可选的相对路径前缀 ./ 或 ../
33
- * - [^\s"'`|)\]]+? 非贪婪匹配路径字符(排除空白、引号、括号等)
34
- * - \.(?:md|markdown) 匹配 .md 或 .markdown 扩展名
35
- * - ) 结束捕获组
36
- *
37
- * 注意:此正则不匹配绝对路径(以 / 开头的路径),需单独处理
38
- */
39
- static RELATIVE_MD_PATH_REGEX = /(?:^|[\s"'`(|\[])((?:\.\/|\.\.\/)+[^\s"'`|)\]]+?\.(?:md|markdown))/gi;
40
- /**
41
- * 匹配绝对路径的正则表达式
42
- * 以 / 开头,匹配 .md 或 .markdown 文件
43
- */
44
- static ABSOLUTE_MD_PATH_REGEX = /(?:^|[\s"'`(|\[])(\/[^\s"'`|)\]]+?\.(?:md|markdown))/gi;
45
- constructor(cwd) {
46
- this.cwd = resolve(cwd);
47
- }
48
- /**
49
- * 去除文本中的 ANSI 转义序列
50
- */
51
- static stripAnsi(text) {
52
- return text.replace(PathDetector.ANSI_ESCAPE_REGEX, '');
53
- }
54
- /**
55
- * 从文本中检测 Markdown 文件路径
56
- *
57
- * @param text - PTY 输出的文本(可能包含 ANSI 转义序列)
58
- * @returns 检测到的路径数组(去重后)
59
- */
60
- detect(text) {
61
- const results = [];
62
- const seen = new Set();
63
- // 入口日志
64
- logger.info({ textLength: text.length }, '[PathDetector] detect() called');
65
- // 先去除 ANSI 转义序列,以便正确匹配路径
66
- const cleanText = PathDetector.stripAnsi(text);
67
- const cleanPreview = cleanText.length > 200 ? cleanText.slice(0, 200) + '...' : cleanText;
68
- logger.info({ cleanTextPreview: cleanPreview }, '[PathDetector] Text after ANSI strip');
69
- // 检测相对路径
70
- let match;
71
- PathDetector.RELATIVE_MD_PATH_REGEX.lastIndex = 0;
72
- let relativeMatchCount = 0;
73
- while ((match = PathDetector.RELATIVE_MD_PATH_REGEX.exec(cleanText)) !== null) {
74
- relativeMatchCount++;
75
- const raw = match[1];
76
- if (seen.has(raw))
77
- continue;
78
- seen.add(raw);
79
- try {
80
- const absolute = resolve(this.cwd, raw);
81
- results.push({
82
- raw,
83
- absolute,
84
- relative: raw,
85
- });
86
- logger.info({ raw, absolute, type: 'relative' }, '[PathDetector] Matched relative path');
87
- }
88
- catch (err) {
89
- logger.info({ raw, err: String(err) }, '[PathDetector] Failed to resolve relative path');
90
- }
91
- }
92
- logger.info({ relativeMatchCount }, '[PathDetector] Relative path matches');
93
- // 检测绝对路径
94
- PathDetector.ABSOLUTE_MD_PATH_REGEX.lastIndex = 0;
95
- let absoluteMatchCount = 0;
96
- while ((match = PathDetector.ABSOLUTE_MD_PATH_REGEX.exec(cleanText)) !== null) {
97
- absoluteMatchCount++;
98
- const raw = match[1];
99
- if (seen.has(raw))
100
- continue;
101
- seen.add(raw);
102
- try {
103
- const absolute = resolve(raw);
104
- // 计算相对于 cwd 的相对路径(如果路径在 cwd 下)
105
- let rel;
106
- const relPath = relative(this.cwd, absolute);
107
- if (!relPath.startsWith('..')) {
108
- rel = relPath;
109
- }
110
- results.push({
111
- raw,
112
- absolute,
113
- relative: rel,
114
- });
115
- logger.info({ raw, absolute, relative: rel, type: 'absolute' }, '[PathDetector] Matched absolute path');
116
- }
117
- catch (err) {
118
- logger.info({ raw, err: String(err) }, '[PathDetector] Failed to resolve absolute path');
119
- }
120
- }
121
- logger.info({ absoluteMatchCount }, '[PathDetector] Absolute path matches');
122
- logger.info({ resultCount: results.length }, '[PathDetector] detect() returning');
123
- return results;
124
- }
125
- /**
126
- * 检查路径是否在允许的目录范围内
127
- *
128
- * @param absolutePath - 要检查的绝对路径
129
- * @param allowedPaths - 允许的目录列表
130
- * @returns 是否允许访问
131
- */
132
- static isPathAllowed(absolutePath, allowedPaths) {
133
- const resolvedPath = resolve(absolutePath);
134
- for (const allowed of allowedPaths) {
135
- const absAllowed = resolve(allowed);
136
- const rel = relative(absAllowed, resolvedPath);
137
- // rel 为空字符串表示路径相同,不以 '..' 开头表示是子目录
138
- if (rel === '' || (rel && !rel.startsWith('..'))) {
139
- return true;
140
- }
141
- }
142
- return false;
143
- }
144
- /**
145
- * 规范化路径,返回绝对路径
146
- *
147
- * @param path - 原始路径
148
- * @param baseDir - 基础目录(用于相对路径解析)
149
- * @returns 解析后的绝对路径,解析失败返回 null
150
- */
151
- static normalizePath(path, baseDir) {
152
- try {
153
- if (isAbsolute(path)) {
154
- return resolve(path);
155
- }
156
- return resolve(baseDir, path);
157
- }
158
- catch {
159
- return null;
160
- }
161
- }
162
- }
163
- //# sourceMappingURL=path-detector.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"path-detector.js","sourceRoot":"","sources":["../../../../backend/src/pty/path-detector.ts"],"names":[],"mappings":"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"}