@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.
- package/README.md +8 -0
- package/dist/backend/src/api/file-routes.d.ts.map +1 -1
- package/dist/backend/src/api/file-routes.js +137 -1
- package/dist/backend/src/api/file-routes.js.map +1 -1
- package/dist/backend/src/cli.js +0 -0
- package/dist/backend/src/index.d.ts.map +1 -1
- package/dist/backend/src/index.js +11 -0
- package/dist/backend/src/index.js.map +1 -1
- package/frontend-dist/assets/index-CVRtrLyp.js +199 -0
- package/frontend-dist/assets/{index-6CW6J4Mw.css → index-UXAwH56Q.css} +1 -1
- package/frontend-dist/index.html +2 -2
- package/package.json +2 -1
- package/dist/backend/src/pty/path-detector.d.ts +0 -83
- package/dist/backend/src/pty/path-detector.d.ts.map +0 -1
- package/dist/backend/src/pty/path-detector.js +0 -163
- package/dist/backend/src/pty/path-detector.js.map +0 -1
- package/frontend-dist/assets/index-CvWXztaS.js +0 -198
|
@@ -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
|
|
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)}}
|
package/frontend-dist/index.html
CHANGED
|
@@ -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-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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.
|
|
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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"}
|