xshell 1.0.104 → 1.0.105
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/Terminal.d.ts +4 -4
- package/Terminal.js +6 -6
- package/git.d.ts +0 -18
- package/git.js +0 -52
- package/i18n/README.md +0 -1
- package/i18n/index.js +1 -3
- package/package.json +8 -10
- package/process.js +1 -3
- package/server.d.ts +1 -0
- package/server.js +13 -2
- package/utils.d.ts +4 -2
- package/utils.js +18 -12
package/Terminal.d.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import 'xterm/css/xterm.css';
|
|
2
|
-
import { Terminal as
|
|
3
|
-
import { FitAddon } from 'xterm
|
|
1
|
+
import '@xterm/xterm/css/xterm.css';
|
|
2
|
+
import { Terminal as XTerminal } from '@xterm/xterm';
|
|
3
|
+
import { FitAddon } from '@xterm/addon-fit';
|
|
4
4
|
import { Model } from 'react-object-model';
|
|
5
5
|
import type { Remote } from './net.browser.js';
|
|
6
6
|
export declare function Terminal({ font }: {
|
|
7
7
|
font: string;
|
|
8
8
|
}): import("react/jsx-runtime").JSX.Element;
|
|
9
9
|
declare class TerminalModel extends Model<TerminalModel> {
|
|
10
|
-
term:
|
|
10
|
+
term: XTerminal;
|
|
11
11
|
fit_addon: FitAddon;
|
|
12
12
|
stdio_id: number;
|
|
13
13
|
fit(): void;
|
package/Terminal.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import 'xterm/css/xterm.css';
|
|
2
|
+
import '@xterm/xterm/css/xterm.css';
|
|
3
3
|
import { useEffect, useRef } from 'react';
|
|
4
|
-
import { Terminal as
|
|
5
|
-
import { FitAddon } from 'xterm
|
|
6
|
-
import { WebglAddon } from 'xterm
|
|
7
|
-
import { WebLinksAddon } from 'xterm
|
|
4
|
+
import { Terminal as XTerminal } from '@xterm/xterm';
|
|
5
|
+
import { FitAddon } from '@xterm/addon-fit';
|
|
6
|
+
import { WebglAddon } from '@xterm/addon-webgl';
|
|
7
|
+
import { WebLinksAddon } from '@xterm/addon-web-links';
|
|
8
8
|
// 没有 ui
|
|
9
9
|
// import { SearchAddon } from 'xterm-addon-search'
|
|
10
10
|
import { Model } from 'react-object-model';
|
|
@@ -14,7 +14,7 @@ export function Terminal({ font }) {
|
|
|
14
14
|
useEffect(() => {
|
|
15
15
|
(async () => {
|
|
16
16
|
await document.fonts.ready;
|
|
17
|
-
let term = new
|
|
17
|
+
let term = new XTerminal({
|
|
18
18
|
fontFamily: font,
|
|
19
19
|
fontSize: 16,
|
|
20
20
|
cursorStyle: 'bar',
|
package/git.d.ts
CHANGED
|
@@ -33,22 +33,4 @@ export declare class Git {
|
|
|
33
33
|
checkout(branch?: 'main'): Promise<void>;
|
|
34
34
|
checkout(branch?: string): Promise<void>;
|
|
35
35
|
_checkout(branch?: string): Promise<void>;
|
|
36
|
-
/** 返回是否进行了修改 */
|
|
37
|
-
merge(branch: string, fast_forward?: boolean): Promise<boolean>;
|
|
38
|
-
/** 记住当前分支名
|
|
39
|
-
checkout 到 <目标分支>
|
|
40
|
-
merge 当前分支 */
|
|
41
|
-
merge_into(target_branch?: string): Promise<void>;
|
|
42
|
-
/** 1. fetch 远程修改
|
|
43
|
-
2. checkout `<branch>` 分支
|
|
44
|
-
3. merge `<remote>/<branch>`
|
|
45
|
-
|
|
46
|
-
执行前需要保证工作目录 clean
|
|
47
|
-
|
|
48
|
-
- branch?: `'main'` */
|
|
49
|
-
update(branch?: 'main'): Promise<void>;
|
|
50
|
-
update(branch: string): Promise<void>;
|
|
51
|
-
update(branch: string, remote?: string): Promise<void>;
|
|
52
|
-
/** - message?: stash description */
|
|
53
|
-
stash(message?: string): Promise<import("./process.js").CallResult<string>>;
|
|
54
36
|
}
|
package/git.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { assert } from './utils.js';
|
|
2
1
|
import { call } from './process.js';
|
|
3
2
|
import { fread, fmkdir } from './file.js';
|
|
4
3
|
export class Git {
|
|
@@ -121,56 +120,5 @@ export class Git {
|
|
|
121
120
|
throw error;
|
|
122
121
|
}
|
|
123
122
|
}
|
|
124
|
-
/** 返回是否进行了修改 */
|
|
125
|
-
async merge(branch, fast_forward = true) {
|
|
126
|
-
console.log(`合并 ${branch} 分支`);
|
|
127
|
-
try {
|
|
128
|
-
const { stdout, stderr } = await this.call([
|
|
129
|
-
'merge',
|
|
130
|
-
branch,
|
|
131
|
-
...fast_forward ? [] : ['--no-ff']
|
|
132
|
-
], { print: false });
|
|
133
|
-
const unchanged = stdout === 'Already up to date.\n';
|
|
134
|
-
if (unchanged)
|
|
135
|
-
console.log('当前分支无需更新');
|
|
136
|
-
else
|
|
137
|
-
console.log(stdout.trimEnd());
|
|
138
|
-
if (stderr)
|
|
139
|
-
console.log(stderr);
|
|
140
|
-
return !unchanged;
|
|
141
|
-
}
|
|
142
|
-
catch (error) {
|
|
143
|
-
if (error.result) {
|
|
144
|
-
const { stdout, stderr } = error.result;
|
|
145
|
-
if (stdout)
|
|
146
|
-
console.log(stdout);
|
|
147
|
-
if (stderr)
|
|
148
|
-
console.log(stderr);
|
|
149
|
-
}
|
|
150
|
-
throw error;
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
/** 记住当前分支名
|
|
154
|
-
checkout 到 <目标分支>
|
|
155
|
-
merge 当前分支 */
|
|
156
|
-
async merge_into(target_branch = 'main') {
|
|
157
|
-
const branch = await this.get_branch();
|
|
158
|
-
assert(branch !== target_branch);
|
|
159
|
-
await this.checkout(target_branch);
|
|
160
|
-
await this.merge(branch, true);
|
|
161
|
-
}
|
|
162
|
-
async update(branch = 'main', remote) {
|
|
163
|
-
await this.fetch({ remote });
|
|
164
|
-
await this.checkout(branch);
|
|
165
|
-
await this.merge(`${remote || 'origin'}/${branch}`);
|
|
166
|
-
}
|
|
167
|
-
/** - message?: stash description */
|
|
168
|
-
async stash(message) {
|
|
169
|
-
return this.call([
|
|
170
|
-
'stash',
|
|
171
|
-
'push',
|
|
172
|
-
...message ? ['--message', message] : [],
|
|
173
|
-
]);
|
|
174
|
-
}
|
|
175
123
|
}
|
|
176
124
|
//# sourceMappingURL=git.js.map
|
package/i18n/README.md
CHANGED
package/i18n/index.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import Cookies from 'js-cookie';
|
|
2
1
|
import { default as i18next } from 'i18next';
|
|
3
2
|
import { Dict } from './dict.js';
|
|
4
3
|
export const LANGUAGES = ['zh', 'en', 'ja', 'ko'];
|
|
@@ -35,8 +34,7 @@ export class I18N {
|
|
|
35
34
|
const dict = new Dict(_dict);
|
|
36
35
|
if (!language && is_browser)
|
|
37
36
|
language = (new URLSearchParams(location.search).get('language') ||
|
|
38
|
-
window.language
|
|
39
|
-
Cookies.get('language'));
|
|
37
|
+
window.language);
|
|
40
38
|
if (!language)
|
|
41
39
|
language = Intl.DateTimeFormat().resolvedOptions().locale.slice(0, 2);
|
|
42
40
|
if (!I18N.LANGUAGE_REGEXP.test(language)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "xshell",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.105",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./index.js",
|
|
6
6
|
"bin": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"interactive programming"
|
|
17
17
|
],
|
|
18
18
|
"engines": {
|
|
19
|
-
"node": ">=
|
|
19
|
+
"node": ">=22.2.0",
|
|
20
20
|
"vscode": ">=1.81.0"
|
|
21
21
|
},
|
|
22
22
|
"scripts": {
|
|
@@ -61,6 +61,10 @@
|
|
|
61
61
|
"@typescript-eslint/eslint-plugin": "^7.9.0",
|
|
62
62
|
"@typescript-eslint/parser": "^7.9.0",
|
|
63
63
|
"@typescript-eslint/utils": "^7.9.0",
|
|
64
|
+
"@xterm/addon-fit": "^0.10.0",
|
|
65
|
+
"@xterm/addon-web-links": "^0.11.0",
|
|
66
|
+
"@xterm/addon-webgl": "^0.18.0",
|
|
67
|
+
"@xterm/xterm": "^5.5.0",
|
|
64
68
|
"ali-oss": "^6.20.0",
|
|
65
69
|
"archiver": "^7.0.1",
|
|
66
70
|
"byte-size": "^8.1.1",
|
|
@@ -79,7 +83,6 @@
|
|
|
79
83
|
"https-proxy-agent": "^7.0.4",
|
|
80
84
|
"i18next": "^23.11.4",
|
|
81
85
|
"i18next-scanner": "^4.4.0",
|
|
82
|
-
"js-cookie": "^3.0.5",
|
|
83
86
|
"koa": "^2.15.3",
|
|
84
87
|
"koa-compress": "^5.1.1",
|
|
85
88
|
"lodash": "^4.17.21",
|
|
@@ -99,11 +102,7 @@
|
|
|
99
102
|
"undici": "^6.16.1",
|
|
100
103
|
"vinyl": "^3.0.0",
|
|
101
104
|
"vinyl-fs": "^4.0.0",
|
|
102
|
-
"ws": "^8.17.0"
|
|
103
|
-
"xterm": "^5.3.0",
|
|
104
|
-
"xterm-addon-fit": "^0.8.0",
|
|
105
|
-
"xterm-addon-web-links": "^0.9.0",
|
|
106
|
-
"xterm-addon-webgl": "^0.16.0"
|
|
105
|
+
"ws": "^8.17.0"
|
|
107
106
|
},
|
|
108
107
|
"devDependencies": {
|
|
109
108
|
"@babel/types": "^7.24.5",
|
|
@@ -115,10 +114,9 @@
|
|
|
115
114
|
"@types/eslint": "^8.56.10",
|
|
116
115
|
"@types/estree": "^1.0.5",
|
|
117
116
|
"@types/gulp-sort": "^2.0.4",
|
|
118
|
-
"@types/js-cookie": "^3.0.6",
|
|
119
117
|
"@types/koa": "^2.15.0",
|
|
120
118
|
"@types/koa-compress": "^4.0.6",
|
|
121
|
-
"@types/lodash": "^4.17.
|
|
119
|
+
"@types/lodash": "^4.17.4",
|
|
122
120
|
"@types/mime-types": "^2.1.4",
|
|
123
121
|
"@types/node": "^20.12.12",
|
|
124
122
|
"@types/react": "^18.3.2",
|
package/process.js
CHANGED
|
@@ -178,9 +178,7 @@ export async function call(exe, args = [], options = {}) {
|
|
|
178
178
|
- throw_code?: `true` code 不为 0 时是否抛出异常 whether to throw Error when code is not 0 */
|
|
179
179
|
export async function call_nodejs(js, args = [], { inspect, break: _break, ...options } = {}) {
|
|
180
180
|
return call(exe_nodejs, [
|
|
181
|
-
...inspect ? [
|
|
182
|
-
_break ? `--inspect-brk=localhost:${inspect}` : `--inspect=localhost:${inspect}`
|
|
183
|
-
] : [],
|
|
181
|
+
...inspect ? [`--inspect${_break ? '-brk' : ''}=localhost:${inspect}`] : [],
|
|
184
182
|
js,
|
|
185
183
|
...args
|
|
186
184
|
], options);
|
package/server.d.ts
CHANGED
package/server.js
CHANGED
|
@@ -8,7 +8,7 @@ import util from 'util';
|
|
|
8
8
|
// --- my libs
|
|
9
9
|
import { t } from './i18n/instance.js';
|
|
10
10
|
import { request as _request, Remote } from './net.js';
|
|
11
|
-
import { inspect, output_width, assert, range_to_numbers, encode, filter_keys, filter_values } from './utils.js';
|
|
11
|
+
import { inspect, output_width, assert, range_to_numbers, encode, filter_keys, filter_values, consume_stream } from './utils.js';
|
|
12
12
|
import { flist, fread, fstat } from './file.js';
|
|
13
13
|
// ------------ my server
|
|
14
14
|
export class Server {
|
|
@@ -24,6 +24,7 @@ export class Server {
|
|
|
24
24
|
name;
|
|
25
25
|
UAParser;
|
|
26
26
|
js_exts = new Set(['.js', '.mjs', '.cjs']);
|
|
27
|
+
empty_body_statuses = new Set([304, 204, 205]);
|
|
27
28
|
app;
|
|
28
29
|
handler;
|
|
29
30
|
/** 启用 http server */
|
|
@@ -472,7 +473,17 @@ export class Server {
|
|
|
472
473
|
response.status = response_.status;
|
|
473
474
|
response.set(Server.filter_response_headers(response_.headers));
|
|
474
475
|
if (response_.body)
|
|
475
|
-
response.
|
|
476
|
+
// 如果设置了 response.status 为 304 等状态码,koa/application.js#respond() 方法中会执行
|
|
477
|
+
// ctx.body = null
|
|
478
|
+
// response.res.end()
|
|
479
|
+
// 而 res.end() 会触发 res 流的 finish, 然后由于之前 response.body = response_.body 这条语句
|
|
480
|
+
// 关联了 response_.body 到 res 的 finish 事件,(koa/response.js#set body() 中 onFinish(res, destroy.bind(null, response_.body))
|
|
481
|
+
// 会让 response_.body 这个 UndiciBodyReadable 被提前 finish,而此时
|
|
482
|
+
// 流还没 emit end, 会触发错误 RequestAbortedError [AbortError]: Request aborted
|
|
483
|
+
if (this.empty_body_statuses.has(response_.status))
|
|
484
|
+
consume_stream(response_.body, true);
|
|
485
|
+
else
|
|
486
|
+
response.body = response_.body;
|
|
476
487
|
}
|
|
477
488
|
catch (error) {
|
|
478
489
|
if (error.response?.status !== 404)
|
package/utils.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export declare function map_values<TValue, TNewValue>(obj: {
|
|
|
34
34
|
};
|
|
35
35
|
/** 过滤对象中的 keys, 返回新对象 */
|
|
36
36
|
export declare function filter_keys<TObj>(obj: TObj, filter: (key: string) => any): TObj;
|
|
37
|
-
/** 过滤对象中的
|
|
37
|
+
/** 过滤对象中的 values, 返回新对象 */
|
|
38
38
|
export declare function filter_values<TObj extends Record<string, any>>(obj: TObj, filter?: (value: TObj[string]) => any): TObj;
|
|
39
39
|
/** 忽略对象中的 keys, 返回新对象 */
|
|
40
40
|
export declare function omit<TObj>(obj: TObj, omit_keys: string[]): TObj;
|
|
@@ -147,7 +147,7 @@ export declare function map_stream<Out, In = Vinyl>(mapper: (obj: In, cb: Functi
|
|
|
147
147
|
failures?: boolean;
|
|
148
148
|
}): Duplex;
|
|
149
149
|
export declare function stream_to_lines(stream: Readable): AsyncGenerator<string, void, unknown>;
|
|
150
|
-
export declare function pipe_with_error(readable: Readable,
|
|
150
|
+
export declare function pipe_with_error<TWritable extends Writable>(readable: Readable, writable: TWritable): TWritable;
|
|
151
151
|
export declare class WritableMemoryStream extends Writable {
|
|
152
152
|
chunks: Buffer[];
|
|
153
153
|
pbuffer: Deferred<Buffer>;
|
|
@@ -168,6 +168,8 @@ export declare class DecoderStream extends Transform {
|
|
|
168
168
|
_transform(chunk: Uint8Array, encoding: BufferEncoding, callback: TransformCallback): void;
|
|
169
169
|
_flush(callback: TransformCallback): void;
|
|
170
170
|
}
|
|
171
|
+
/** 消费一个可读流 */
|
|
172
|
+
export declare function consume_stream(stream: Readable, ignore_error?: boolean): Promise<void>;
|
|
171
173
|
/** 根据 range 生成整数序列 (iterable)
|
|
172
174
|
- range: 取值为逗号分割的多个可用值或值区间 (不能含有空格),比如:`8321,8322,8300-8310,11000-11999`
|
|
173
175
|
- reverse?: `false` 在 range 内从后往前生成 */
|
package/utils.js
CHANGED
|
@@ -80,7 +80,7 @@ export function filter_keys(obj, filter) {
|
|
|
80
80
|
return Object.fromEntries(Object.entries(obj)
|
|
81
81
|
.filter(([key]) => filter(key)));
|
|
82
82
|
}
|
|
83
|
-
/** 过滤对象中的
|
|
83
|
+
/** 过滤对象中的 values, 返回新对象 */
|
|
84
84
|
export function filter_values(obj, filter = not_empty) {
|
|
85
85
|
return Object.fromEntries(Object.entries(obj)
|
|
86
86
|
.filter(([, value]) => filter(value)));
|
|
@@ -218,18 +218,13 @@ export async function timeout(milliseconds, action) {
|
|
|
218
218
|
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
219
219
|
export function defer(initial) {
|
|
220
220
|
if (initial === undefined) {
|
|
221
|
-
let resolve;
|
|
222
|
-
let reject;
|
|
223
|
-
let promise = new Promise((_resolve, _reject) => {
|
|
224
|
-
resolve = _resolve;
|
|
225
|
-
reject = _reject;
|
|
226
|
-
});
|
|
221
|
+
let { promise, resolve, reject } = Promise.withResolvers();
|
|
227
222
|
return Object.assign(promise, { resolve, reject });
|
|
228
223
|
}
|
|
229
224
|
else
|
|
230
225
|
return Object.assign(Promise.resolve(initial), {
|
|
231
|
-
resolve
|
|
232
|
-
reject
|
|
226
|
+
resolve: noop,
|
|
227
|
+
reject: noop
|
|
233
228
|
});
|
|
234
229
|
}
|
|
235
230
|
/** @example
|
|
@@ -476,10 +471,10 @@ export async function* stream_to_lines(stream) {
|
|
|
476
471
|
buf = chunk.slice(j);
|
|
477
472
|
}
|
|
478
473
|
}
|
|
479
|
-
export function pipe_with_error(readable,
|
|
474
|
+
export function pipe_with_error(readable, writable) {
|
|
480
475
|
// 不知道 transform 作为 AsyncIterable 使用时, emit error 是否会在 for await (...) 循环中触发错误
|
|
481
|
-
readable.once('error', error => {
|
|
482
|
-
return readable.pipe(
|
|
476
|
+
readable.once('error', error => { writable.emit('error', error); });
|
|
477
|
+
return readable.pipe(writable);
|
|
483
478
|
}
|
|
484
479
|
export class WritableMemoryStream extends Writable {
|
|
485
480
|
chunks = [];
|
|
@@ -525,6 +520,17 @@ export class DecoderStream extends Transform {
|
|
|
525
520
|
callback();
|
|
526
521
|
}
|
|
527
522
|
}
|
|
523
|
+
/** 消费一个可读流 */
|
|
524
|
+
export async function consume_stream(stream, ignore_error = false) {
|
|
525
|
+
try {
|
|
526
|
+
for await (const chunk of stream)
|
|
527
|
+
;
|
|
528
|
+
}
|
|
529
|
+
catch (error) {
|
|
530
|
+
if (!ignore_error)
|
|
531
|
+
throw error;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
528
534
|
/** 根据 range 生成整数序列 (iterable)
|
|
529
535
|
- range: 取值为逗号分割的多个可用值或值区间 (不能含有空格),比如:`8321,8322,8300-8310,11000-11999`
|
|
530
536
|
- reverse?: `false` 在 range 内从后往前生成 */
|