@qodalis/cli-scp 2.0.0-beta.2 → 2.0.0-beta.21
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/package.json +2 -2
- package/public-api.d.mts +6 -3
- package/public-api.d.ts +6 -3
- package/public-api.js +127 -108
- package/public-api.js.map +1 -1
- package/public-api.mjs +128 -109
- package/public-api.mjs.map +1 -1
- package/umd/index.global.js +356 -165
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@qodalis/cli-scp",
|
|
3
|
-
"version": "2.0.0-beta.
|
|
3
|
+
"version": "2.0.0-beta.21",
|
|
4
4
|
"description": "SCP-like file transfer between browser and remote servers",
|
|
5
5
|
"author": "Qodalis Solutions",
|
|
6
6
|
"license": "MIT",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"umd": "./umd/index.global.js",
|
|
19
19
|
"unpkg": "./umd/index.global.js",
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@qodalis/cli-core": "2.0.0-beta.
|
|
21
|
+
"@qodalis/cli-core": "2.0.0-beta.21"
|
|
22
22
|
},
|
|
23
23
|
"sideEffects": false,
|
|
24
24
|
"main": "./public-api.js",
|
package/public-api.d.mts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import * as _qodalis_cli_core from '@qodalis/cli-core';
|
|
2
1
|
import { ICliCommandProcessor, ICliCommandChildProcessor, CliProcessCommand, ICliExecutionContext, ICliModule } from '@qodalis/cli-core';
|
|
3
2
|
|
|
4
3
|
declare class CliScpCommandCommandProcessor implements ICliCommandProcessor {
|
|
5
4
|
command: string;
|
|
6
5
|
description: string;
|
|
7
|
-
author:
|
|
6
|
+
author: any;
|
|
8
7
|
version: string;
|
|
8
|
+
metadata: {
|
|
9
|
+
icon: string;
|
|
10
|
+
module: string;
|
|
11
|
+
};
|
|
9
12
|
acceptsRawInput: boolean;
|
|
10
13
|
processors: ICliCommandChildProcessor[];
|
|
11
14
|
processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
|
|
@@ -14,7 +17,7 @@ declare class CliScpCommandCommandProcessor implements ICliCommandProcessor {
|
|
|
14
17
|
private doUpload;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
|
-
declare const LIBRARY_VERSION = "2.0.0-beta.
|
|
20
|
+
declare const LIBRARY_VERSION = "2.0.0-beta.21";
|
|
18
21
|
declare const API_VERSION = 2;
|
|
19
22
|
|
|
20
23
|
declare const scpModule: ICliModule;
|
package/public-api.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
|
-
import * as _qodalis_cli_core from '@qodalis/cli-core';
|
|
2
1
|
import { ICliCommandProcessor, ICliCommandChildProcessor, CliProcessCommand, ICliExecutionContext, ICliModule } from '@qodalis/cli-core';
|
|
3
2
|
|
|
4
3
|
declare class CliScpCommandCommandProcessor implements ICliCommandProcessor {
|
|
5
4
|
command: string;
|
|
6
5
|
description: string;
|
|
7
|
-
author:
|
|
6
|
+
author: any;
|
|
8
7
|
version: string;
|
|
8
|
+
metadata: {
|
|
9
|
+
icon: string;
|
|
10
|
+
module: string;
|
|
11
|
+
};
|
|
9
12
|
acceptsRawInput: boolean;
|
|
10
13
|
processors: ICliCommandChildProcessor[];
|
|
11
14
|
processCommand(command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
|
|
@@ -14,7 +17,7 @@ declare class CliScpCommandCommandProcessor implements ICliCommandProcessor {
|
|
|
14
17
|
private doUpload;
|
|
15
18
|
}
|
|
16
19
|
|
|
17
|
-
declare const LIBRARY_VERSION = "2.0.0-beta.
|
|
20
|
+
declare const LIBRARY_VERSION = "2.0.0-beta.21";
|
|
18
21
|
declare const API_VERSION = 2;
|
|
19
22
|
|
|
20
23
|
declare const scpModule: ICliModule;
|
package/public-api.js
CHANGED
|
@@ -5,13 +5,9 @@ var cliCore = require('@qodalis/cli-core');
|
|
|
5
5
|
// src/lib/processors/cli-scp-command-processor.ts
|
|
6
6
|
|
|
7
7
|
// src/lib/version.ts
|
|
8
|
-
var LIBRARY_VERSION = "2.0.0-beta.
|
|
8
|
+
var LIBRARY_VERSION = "2.0.0-beta.21";
|
|
9
9
|
var API_VERSION = 2;
|
|
10
|
-
|
|
11
|
-
// src/lib/interfaces/index.ts
|
|
12
|
-
var IScpTransferService_TOKEN = "scp-transfer-service";
|
|
13
|
-
|
|
14
|
-
// src/lib/processors/scp-utils.ts
|
|
10
|
+
var IScpTransferService_TOKEN = cliCore.createCliToken("scp-transfer-service");
|
|
15
11
|
function resolveServer(serverName, context) {
|
|
16
12
|
const servers = context.options?.servers;
|
|
17
13
|
if (!servers || servers.length === 0) {
|
|
@@ -49,10 +45,10 @@ function parseServerAndPath(value, context, args) {
|
|
|
49
45
|
if (serverArg && pathArg) {
|
|
50
46
|
return [String(serverArg), String(pathArg)];
|
|
51
47
|
}
|
|
52
|
-
|
|
48
|
+
const parts = cliCore.splitShellWords(value ?? "");
|
|
49
|
+
if (parts.length === 0) {
|
|
53
50
|
return null;
|
|
54
51
|
}
|
|
55
|
-
const parts = value.trim().split(/\s+/);
|
|
56
52
|
if (parts.length < 2) {
|
|
57
53
|
if (serverArg && parts.length >= 1) {
|
|
58
54
|
return [String(serverArg), parts.join(" ")];
|
|
@@ -64,8 +60,6 @@ function parseServerAndPath(value, context, args) {
|
|
|
64
60
|
}
|
|
65
61
|
return [parts[0], parts.slice(1).join(" ")];
|
|
66
62
|
}
|
|
67
|
-
|
|
68
|
-
// src/lib/processors/cli-scp-ls-processor.ts
|
|
69
63
|
var CliScpLsProcessor = class {
|
|
70
64
|
constructor() {
|
|
71
65
|
this.command = "ls";
|
|
@@ -96,7 +90,7 @@ var CliScpLsProcessor = class {
|
|
|
96
90
|
const [serverName, path] = parsed;
|
|
97
91
|
const server = resolveServer(serverName, context);
|
|
98
92
|
if (!server) return;
|
|
99
|
-
const transferService = context.services.
|
|
93
|
+
const transferService = context.services.getRequired(
|
|
100
94
|
IScpTransferService_TOKEN
|
|
101
95
|
);
|
|
102
96
|
if (!transferService) {
|
|
@@ -108,7 +102,7 @@ var CliScpLsProcessor = class {
|
|
|
108
102
|
const entries = await transferService.ls(
|
|
109
103
|
serverUrl(server),
|
|
110
104
|
path,
|
|
111
|
-
server.headers
|
|
105
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers)
|
|
112
106
|
);
|
|
113
107
|
context.spinner?.hide();
|
|
114
108
|
if (entries.length === 0) {
|
|
@@ -133,8 +127,6 @@ var CliScpLsProcessor = class {
|
|
|
133
127
|
context.writer.writeln("List files and directories on a remote server.");
|
|
134
128
|
}
|
|
135
129
|
};
|
|
136
|
-
|
|
137
|
-
// src/lib/processors/cli-scp-cat-processor.ts
|
|
138
130
|
var CliScpCatProcessor = class {
|
|
139
131
|
constructor() {
|
|
140
132
|
this.command = "cat";
|
|
@@ -165,7 +157,7 @@ var CliScpCatProcessor = class {
|
|
|
165
157
|
const [serverName, path] = parsed;
|
|
166
158
|
const server = resolveServer(serverName, context);
|
|
167
159
|
if (!server) return;
|
|
168
|
-
const transferService = context.services.
|
|
160
|
+
const transferService = context.services.getRequired(
|
|
169
161
|
IScpTransferService_TOKEN
|
|
170
162
|
);
|
|
171
163
|
if (!transferService) {
|
|
@@ -177,7 +169,7 @@ var CliScpCatProcessor = class {
|
|
|
177
169
|
const content = await transferService.cat(
|
|
178
170
|
serverUrl(server),
|
|
179
171
|
path,
|
|
180
|
-
server.headers
|
|
172
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers)
|
|
181
173
|
);
|
|
182
174
|
context.spinner?.hide();
|
|
183
175
|
context.writer.writeln(content);
|
|
@@ -235,12 +227,11 @@ var CliScpDownloadProcessor = class {
|
|
|
235
227
|
remotePath = String(args["remote-path"] || args["path"]);
|
|
236
228
|
localPath = args["local-path"] ? String(args["local-path"]) : void 0;
|
|
237
229
|
} else {
|
|
238
|
-
const
|
|
239
|
-
if (
|
|
230
|
+
const parts = command.positionals ?? [];
|
|
231
|
+
if (parts.length === 0) {
|
|
240
232
|
context.writer.writeError("Usage: scp download <server> <remote-path> [local-path]");
|
|
241
233
|
return;
|
|
242
234
|
}
|
|
243
|
-
const parts = value.split(/\s+/);
|
|
244
235
|
if (parts.length < 2) {
|
|
245
236
|
context.writer.writeError("Usage: scp download <server> <remote-path> [local-path]");
|
|
246
237
|
return;
|
|
@@ -256,7 +247,7 @@ var CliScpDownloadProcessor = class {
|
|
|
256
247
|
localPath = localPath || remotePath.split("/").pop() || "download";
|
|
257
248
|
const server = resolveServer(serverName, context);
|
|
258
249
|
if (!server) return;
|
|
259
|
-
const transferService = context.services.
|
|
250
|
+
const transferService = context.services.getRequired(
|
|
260
251
|
IScpTransferService_TOKEN
|
|
261
252
|
);
|
|
262
253
|
if (!transferService) {
|
|
@@ -265,6 +256,7 @@ var CliScpDownloadProcessor = class {
|
|
|
265
256
|
}
|
|
266
257
|
const useBrowserDownload = command.args?.["save"] === true;
|
|
267
258
|
context.spinner?.show(`Downloading ${remotePath} from ${server.name}...`);
|
|
259
|
+
context.notifier.info(`scp: downloading from ${server.name}`);
|
|
268
260
|
const abortController = new AbortController();
|
|
269
261
|
const abortSub = context.onAbort.subscribe(() => abortController.abort());
|
|
270
262
|
try {
|
|
@@ -272,7 +264,7 @@ var CliScpDownloadProcessor = class {
|
|
|
272
264
|
const { content, size } = await transferService.download(
|
|
273
265
|
serverUrl(server),
|
|
274
266
|
remotePath,
|
|
275
|
-
server.headers,
|
|
267
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers),
|
|
276
268
|
(received, total) => {
|
|
277
269
|
const now = Date.now();
|
|
278
270
|
if (now - lastProgressUpdate < 200) return;
|
|
@@ -282,17 +274,19 @@ var CliScpDownloadProcessor = class {
|
|
|
282
274
|
context.spinner?.show(
|
|
283
275
|
`Downloading ${remotePath}... ${pct}% (${formatBytes(received)}/${formatBytes(total)})`
|
|
284
276
|
);
|
|
277
|
+
context.notifier.info(`scp: download ${pct}%`);
|
|
285
278
|
} else {
|
|
286
279
|
context.spinner?.show(
|
|
287
280
|
`Downloading ${remotePath}... ${formatBytes(received)}`
|
|
288
281
|
);
|
|
282
|
+
context.notifier.info(`scp: download ${formatBytes(received)}`);
|
|
289
283
|
}
|
|
290
284
|
},
|
|
291
285
|
abortController.signal
|
|
292
286
|
);
|
|
293
287
|
context.spinner?.hide();
|
|
294
288
|
if (useBrowserDownload) {
|
|
295
|
-
const fileService = context.services.
|
|
289
|
+
const fileService = context.services.getRequired(
|
|
296
290
|
cliCore.ICliFileTransferService_TOKEN
|
|
297
291
|
);
|
|
298
292
|
if (fileService) {
|
|
@@ -304,7 +298,7 @@ var CliScpDownloadProcessor = class {
|
|
|
304
298
|
context.writer.writeError("File transfer service not available for browser download.");
|
|
305
299
|
}
|
|
306
300
|
} else {
|
|
307
|
-
const fileService = context.services.
|
|
301
|
+
const fileService = context.services.getRequired(
|
|
308
302
|
cliCore.ICliFileTransferService_TOKEN
|
|
309
303
|
);
|
|
310
304
|
if (fileService) {
|
|
@@ -333,7 +327,7 @@ var CliScpUploadProcessor = class {
|
|
|
333
327
|
constructor() {
|
|
334
328
|
this.command = "upload";
|
|
335
329
|
this.aliases = ["put"];
|
|
336
|
-
this.description = "Upload a
|
|
330
|
+
this.description = "Upload a file to a remote server (use --local to pick from your machine)";
|
|
337
331
|
this.acceptsRawInput = true;
|
|
338
332
|
this.valueRequired = true;
|
|
339
333
|
this.parameters = [
|
|
@@ -345,8 +339,8 @@ var CliScpUploadProcessor = class {
|
|
|
345
339
|
},
|
|
346
340
|
{
|
|
347
341
|
name: "local-path",
|
|
348
|
-
description: "Local file path",
|
|
349
|
-
required:
|
|
342
|
+
description: "Local file path (from virtual filesystem)",
|
|
343
|
+
required: false,
|
|
350
344
|
type: "string"
|
|
351
345
|
},
|
|
352
346
|
{
|
|
@@ -354,71 +348,103 @@ var CliScpUploadProcessor = class {
|
|
|
354
348
|
description: "Remote destination path",
|
|
355
349
|
required: true,
|
|
356
350
|
type: "string"
|
|
351
|
+
},
|
|
352
|
+
{
|
|
353
|
+
name: "local",
|
|
354
|
+
description: "Pick a file from your local machine via browser file picker",
|
|
355
|
+
required: false,
|
|
356
|
+
type: "boolean"
|
|
357
357
|
}
|
|
358
358
|
];
|
|
359
359
|
}
|
|
360
360
|
async processCommand(command, context) {
|
|
361
361
|
const args = command.args || {};
|
|
362
|
+
const useLocalPicker = !!args["local"];
|
|
362
363
|
let serverName;
|
|
363
364
|
let localPath;
|
|
364
365
|
let remotePath;
|
|
365
|
-
if (args["server"] && args["
|
|
366
|
+
if (args["server"] && args["remote-path"]) {
|
|
366
367
|
serverName = String(args["server"]);
|
|
367
|
-
localPath = String(args["local-path"]);
|
|
368
|
+
localPath = args["local-path"] ? String(args["local-path"]) : void 0;
|
|
368
369
|
remotePath = String(args["remote-path"]);
|
|
369
370
|
} else {
|
|
370
|
-
const
|
|
371
|
-
if (
|
|
372
|
-
context.writer.writeError(
|
|
371
|
+
const parts = command.positionals ?? [];
|
|
372
|
+
if (parts.length === 0) {
|
|
373
|
+
context.writer.writeError(
|
|
374
|
+
useLocalPicker ? "Usage: scp upload --local <server> <remote-path>" : "Usage: scp upload <server> <local-path> <remote-path>"
|
|
375
|
+
);
|
|
373
376
|
return;
|
|
374
377
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
378
|
+
if (useLocalPicker) {
|
|
379
|
+
if (parts.length < 2) {
|
|
380
|
+
context.writer.writeError("Usage: scp upload --local <server> <remote-path>");
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
serverName = parts[0];
|
|
384
|
+
remotePath = parts[1];
|
|
385
|
+
} else {
|
|
386
|
+
if (parts.length < 3) {
|
|
387
|
+
context.writer.writeError("Usage: scp upload <server> <local-path> <remote-path>");
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
serverName = parts[0];
|
|
391
|
+
localPath = parts[1];
|
|
392
|
+
remotePath = parts[2];
|
|
379
393
|
}
|
|
380
|
-
serverName = parts[0];
|
|
381
|
-
localPath = parts[1];
|
|
382
|
-
remotePath = parts[2];
|
|
383
394
|
}
|
|
384
|
-
if (!serverName || !localPath || !remotePath) {
|
|
385
|
-
context.writer.writeError(
|
|
395
|
+
if (!serverName || !useLocalPicker && !localPath || !remotePath) {
|
|
396
|
+
context.writer.writeError(
|
|
397
|
+
useLocalPicker ? "Usage: scp upload --local <server> <remote-path>" : "Usage: scp upload <server> <local-path> <remote-path>"
|
|
398
|
+
);
|
|
386
399
|
return;
|
|
387
400
|
}
|
|
388
401
|
const server = resolveServer(serverName, context);
|
|
389
402
|
if (!server) return;
|
|
390
|
-
const fileService = context.services.
|
|
403
|
+
const fileService = context.services.getRequired(
|
|
391
404
|
cliCore.ICliFileTransferService_TOKEN
|
|
392
405
|
);
|
|
393
406
|
if (!fileService) {
|
|
394
407
|
context.writer.writeError("File transfer service not available.");
|
|
395
408
|
return;
|
|
396
409
|
}
|
|
397
|
-
const transferService = context.services.
|
|
410
|
+
const transferService = context.services.getRequired(
|
|
398
411
|
IScpTransferService_TOKEN
|
|
399
412
|
);
|
|
400
413
|
if (!transferService) {
|
|
401
414
|
context.writer.writeError("SCP transfer service not available.");
|
|
402
415
|
return;
|
|
403
416
|
}
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
417
|
+
let content;
|
|
418
|
+
let filename;
|
|
419
|
+
if (useLocalPicker) {
|
|
420
|
+
const picked = await fileService.uploadFromBrowser();
|
|
421
|
+
if (!picked) {
|
|
422
|
+
context.writer.writeln("Upload cancelled.");
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
content = picked.content;
|
|
426
|
+
filename = picked.name;
|
|
427
|
+
} else {
|
|
428
|
+
context.spinner?.show(`Reading local file "${localPath}"...`);
|
|
429
|
+
content = await fileService.readFile(localPath);
|
|
407
430
|
if (content === null) {
|
|
408
431
|
context.spinner?.hide();
|
|
409
432
|
context.writer.writeError(`Local file not found: ${localPath}`);
|
|
410
433
|
return;
|
|
411
434
|
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
)
|
|
435
|
+
filename = localPath.split("/").pop() || "file";
|
|
436
|
+
}
|
|
437
|
+
context.spinner?.show(
|
|
438
|
+
`Uploading "${filename}" (${formatBytes(content.length)}) to ${server.name}:${remotePath}...`
|
|
439
|
+
);
|
|
440
|
+
context.notifier.info(`scp: uploading to ${server.name}`);
|
|
441
|
+
try {
|
|
416
442
|
await transferService.upload(
|
|
417
443
|
serverUrl(server),
|
|
418
444
|
remotePath,
|
|
419
445
|
content,
|
|
420
446
|
filename,
|
|
421
|
-
server.headers
|
|
447
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers)
|
|
422
448
|
);
|
|
423
449
|
context.spinner?.hide();
|
|
424
450
|
context.writer.writeSuccess(
|
|
@@ -430,12 +456,13 @@ var CliScpUploadProcessor = class {
|
|
|
430
456
|
}
|
|
431
457
|
}
|
|
432
458
|
writeDescription(context) {
|
|
433
|
-
context.writer.writeln("Upload a
|
|
434
|
-
context.writer.writeln("
|
|
459
|
+
context.writer.writeln("Upload a file to a remote server.");
|
|
460
|
+
context.writer.writeln("");
|
|
461
|
+
context.writer.writeln("Usage:");
|
|
462
|
+
context.writer.writeln(" scp upload <server> <local-path> <remote-path> Upload from virtual filesystem");
|
|
463
|
+
context.writer.writeln(" scp upload --local <server> <remote-path> Pick from your machine via browser");
|
|
435
464
|
}
|
|
436
465
|
};
|
|
437
|
-
|
|
438
|
-
// src/lib/processors/cli-scp-rm-processor.ts
|
|
439
466
|
var CliScpRmProcessor = class {
|
|
440
467
|
constructor() {
|
|
441
468
|
this.command = "rm";
|
|
@@ -466,7 +493,7 @@ var CliScpRmProcessor = class {
|
|
|
466
493
|
const [serverName, path] = parsed;
|
|
467
494
|
const server = resolveServer(serverName, context);
|
|
468
495
|
if (!server) return;
|
|
469
|
-
const transferService = context.services.
|
|
496
|
+
const transferService = context.services.getRequired(
|
|
470
497
|
IScpTransferService_TOKEN
|
|
471
498
|
);
|
|
472
499
|
if (!transferService) {
|
|
@@ -478,7 +505,7 @@ var CliScpRmProcessor = class {
|
|
|
478
505
|
await transferService.rm(
|
|
479
506
|
serverUrl(server),
|
|
480
507
|
path,
|
|
481
|
-
server.headers
|
|
508
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers)
|
|
482
509
|
);
|
|
483
510
|
context.spinner?.hide();
|
|
484
511
|
context.writer.writeSuccess(`Deleted: ${server.name}:${path}`);
|
|
@@ -491,8 +518,6 @@ var CliScpRmProcessor = class {
|
|
|
491
518
|
context.writer.writeln("Delete a file on a remote server.");
|
|
492
519
|
}
|
|
493
520
|
};
|
|
494
|
-
|
|
495
|
-
// src/lib/processors/cli-scp-mkdir-processor.ts
|
|
496
521
|
var CliScpMkdirProcessor = class {
|
|
497
522
|
constructor() {
|
|
498
523
|
this.command = "mkdir";
|
|
@@ -523,7 +548,7 @@ var CliScpMkdirProcessor = class {
|
|
|
523
548
|
const [serverName, path] = parsed;
|
|
524
549
|
const server = resolveServer(serverName, context);
|
|
525
550
|
if (!server) return;
|
|
526
|
-
const transferService = context.services.
|
|
551
|
+
const transferService = context.services.getRequired(
|
|
527
552
|
IScpTransferService_TOKEN
|
|
528
553
|
);
|
|
529
554
|
if (!transferService) {
|
|
@@ -535,7 +560,7 @@ var CliScpMkdirProcessor = class {
|
|
|
535
560
|
await transferService.mkdir(
|
|
536
561
|
serverUrl(server),
|
|
537
562
|
path,
|
|
538
|
-
server.headers
|
|
563
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers)
|
|
539
564
|
);
|
|
540
565
|
context.spinner?.hide();
|
|
541
566
|
context.writer.writeSuccess(`Created directory: ${server.name}:${path}`);
|
|
@@ -548,8 +573,6 @@ var CliScpMkdirProcessor = class {
|
|
|
548
573
|
context.writer.writeln("Create a directory on a remote server.");
|
|
549
574
|
}
|
|
550
575
|
};
|
|
551
|
-
|
|
552
|
-
// src/lib/processors/cli-scp-stat-processor.ts
|
|
553
576
|
var CliScpStatProcessor = class {
|
|
554
577
|
constructor() {
|
|
555
578
|
this.command = "stat";
|
|
@@ -580,7 +603,7 @@ var CliScpStatProcessor = class {
|
|
|
580
603
|
const [serverName, path] = parsed;
|
|
581
604
|
const server = resolveServer(serverName, context);
|
|
582
605
|
if (!server) return;
|
|
583
|
-
const transferService = context.services.
|
|
606
|
+
const transferService = context.services.getRequired(
|
|
584
607
|
IScpTransferService_TOKEN
|
|
585
608
|
);
|
|
586
609
|
if (!transferService) {
|
|
@@ -592,7 +615,7 @@ var CliScpStatProcessor = class {
|
|
|
592
615
|
const stat = await transferService.stat(
|
|
593
616
|
serverUrl(server),
|
|
594
617
|
path,
|
|
595
|
-
server.headers
|
|
618
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers)
|
|
596
619
|
);
|
|
597
620
|
context.spinner?.hide();
|
|
598
621
|
const entries = {
|
|
@@ -623,6 +646,7 @@ var CliScpCommandCommandProcessor = class {
|
|
|
623
646
|
this.description = "SCP-like file transfer between browser and remote servers";
|
|
624
647
|
this.author = cliCore.DefaultLibraryAuthor;
|
|
625
648
|
this.version = LIBRARY_VERSION;
|
|
649
|
+
this.metadata = { icon: "\u{1F4C1}", module: "file management" };
|
|
626
650
|
this.acceptsRawInput = true;
|
|
627
651
|
this.processors = [
|
|
628
652
|
new CliScpLsProcessor(),
|
|
@@ -635,33 +659,25 @@ var CliScpCommandCommandProcessor = class {
|
|
|
635
659
|
];
|
|
636
660
|
}
|
|
637
661
|
async processCommand(command, context) {
|
|
638
|
-
const
|
|
639
|
-
if (
|
|
640
|
-
const colonIdx =
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
const
|
|
644
|
-
const
|
|
645
|
-
const parts2 = rest.trim().split(/\s+/);
|
|
646
|
-
const remotePath = parts2[0];
|
|
647
|
-
const localPath = parts2[1] || remotePath.split("/").pop() || "download";
|
|
662
|
+
const [first = "", second] = command.positionals ?? [];
|
|
663
|
+
if (first && !first.startsWith("-")) {
|
|
664
|
+
const colonIdx = first.indexOf(":");
|
|
665
|
+
if (colonIdx !== -1) {
|
|
666
|
+
const serverName = first.substring(0, colonIdx);
|
|
667
|
+
const remotePath = first.substring(colonIdx + 1);
|
|
668
|
+
const localPath = second || remotePath.split("/").pop() || "download";
|
|
648
669
|
if (remotePath) {
|
|
649
670
|
await this.doDownload(serverName, remotePath, localPath, command, context);
|
|
650
671
|
return;
|
|
651
672
|
}
|
|
652
673
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
const
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
const remotePath = secondPart.substring(srvColonIdx + 1);
|
|
661
|
-
if (remotePath) {
|
|
662
|
-
await this.doUpload(serverName, localPath, remotePath, context);
|
|
663
|
-
return;
|
|
664
|
-
}
|
|
674
|
+
if (second?.includes(":")) {
|
|
675
|
+
const srvColonIdx = second.indexOf(":");
|
|
676
|
+
const serverName = second.substring(0, srvColonIdx);
|
|
677
|
+
const remotePath = second.substring(srvColonIdx + 1);
|
|
678
|
+
if (remotePath) {
|
|
679
|
+
await this.doUpload(serverName, first, remotePath, context);
|
|
680
|
+
return;
|
|
665
681
|
}
|
|
666
682
|
}
|
|
667
683
|
}
|
|
@@ -673,7 +689,7 @@ var CliScpCommandCommandProcessor = class {
|
|
|
673
689
|
async doDownload(serverName, remotePath, localPath, command, context) {
|
|
674
690
|
const server = resolveServer(serverName, context);
|
|
675
691
|
if (!server) return;
|
|
676
|
-
const transferService = context.services.
|
|
692
|
+
const transferService = context.services.getRequired(
|
|
677
693
|
IScpTransferService_TOKEN
|
|
678
694
|
);
|
|
679
695
|
if (!transferService) {
|
|
@@ -682,12 +698,13 @@ var CliScpCommandCommandProcessor = class {
|
|
|
682
698
|
}
|
|
683
699
|
const useBrowserDownload = command.args?.["save"] === true;
|
|
684
700
|
context.spinner?.show(`Downloading ${remotePath} from ${server.name}...`);
|
|
701
|
+
context.notifier.info(`scp: downloading from ${server.name}`);
|
|
685
702
|
try {
|
|
686
703
|
let lastProgressUpdate = 0;
|
|
687
704
|
const { content, size } = await transferService.download(
|
|
688
705
|
serverUrl(server),
|
|
689
706
|
remotePath,
|
|
690
|
-
server.headers,
|
|
707
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers),
|
|
691
708
|
(received, total) => {
|
|
692
709
|
const now = Date.now();
|
|
693
710
|
if (now - lastProgressUpdate < 200) return;
|
|
@@ -697,15 +714,17 @@ var CliScpCommandCommandProcessor = class {
|
|
|
697
714
|
context.spinner?.show(
|
|
698
715
|
`Downloading ${remotePath}... ${pct}% (${formatBytes(received)}/${formatBytes(total)})`
|
|
699
716
|
);
|
|
717
|
+
context.notifier.info(`scp: download ${pct}%`);
|
|
700
718
|
} else {
|
|
701
719
|
context.spinner?.show(
|
|
702
720
|
`Downloading ${remotePath}... ${formatBytes(received)}`
|
|
703
721
|
);
|
|
722
|
+
context.notifier.info(`scp: download ${formatBytes(received)}`);
|
|
704
723
|
}
|
|
705
724
|
}
|
|
706
725
|
);
|
|
707
726
|
context.spinner?.hide();
|
|
708
|
-
const fileService = context.services.
|
|
727
|
+
const fileService = context.services.getRequired(
|
|
709
728
|
cliCore.ICliFileTransferService_TOKEN
|
|
710
729
|
);
|
|
711
730
|
if (!fileService) {
|
|
@@ -731,14 +750,14 @@ var CliScpCommandCommandProcessor = class {
|
|
|
731
750
|
async doUpload(serverName, localPath, remotePath, context) {
|
|
732
751
|
const server = resolveServer(serverName, context);
|
|
733
752
|
if (!server) return;
|
|
734
|
-
const fileService = context.services.
|
|
753
|
+
const fileService = context.services.getRequired(
|
|
735
754
|
cliCore.ICliFileTransferService_TOKEN
|
|
736
755
|
);
|
|
737
756
|
if (!fileService) {
|
|
738
757
|
context.writer.writeError("File transfer service not available.");
|
|
739
758
|
return;
|
|
740
759
|
}
|
|
741
|
-
const transferService = context.services.
|
|
760
|
+
const transferService = context.services.getRequired(
|
|
742
761
|
IScpTransferService_TOKEN
|
|
743
762
|
);
|
|
744
763
|
if (!transferService) {
|
|
@@ -746,6 +765,7 @@ var CliScpCommandCommandProcessor = class {
|
|
|
746
765
|
return;
|
|
747
766
|
}
|
|
748
767
|
context.spinner?.show(`Reading local file "${localPath}"...`);
|
|
768
|
+
context.notifier.info(`scp: reading ${localPath}`);
|
|
749
769
|
try {
|
|
750
770
|
const content = await fileService.readFile(localPath);
|
|
751
771
|
if (content === null) {
|
|
@@ -757,12 +777,13 @@ var CliScpCommandCommandProcessor = class {
|
|
|
757
777
|
context.spinner?.show(
|
|
758
778
|
`Uploading "${filename}" (${formatBytes(content.length)}) to ${server.name}:${remotePath}...`
|
|
759
779
|
);
|
|
780
|
+
context.notifier.info(`scp: uploading to ${server.name}`);
|
|
760
781
|
await transferService.upload(
|
|
761
782
|
serverUrl(server),
|
|
762
783
|
remotePath,
|
|
763
784
|
content,
|
|
764
785
|
filename,
|
|
765
|
-
server.headers
|
|
786
|
+
cliCore.resolveServerHeaders(context.services, server.name, server.headers)
|
|
766
787
|
);
|
|
767
788
|
context.spinner?.hide();
|
|
768
789
|
context.writer.writeSuccess(
|
|
@@ -774,32 +795,30 @@ var CliScpCommandCommandProcessor = class {
|
|
|
774
795
|
}
|
|
775
796
|
}
|
|
776
797
|
};
|
|
777
|
-
|
|
778
|
-
// src/lib/services/scp-transfer.service.ts
|
|
779
798
|
var ScpTransferService = class {
|
|
780
799
|
async ls(serverUrl2, path, headers) {
|
|
781
|
-
const res = await this._fetch(`${serverUrl2}/api/
|
|
782
|
-
headers
|
|
800
|
+
const res = await this._fetch(`${serverUrl2}/api/qcli/fs/ls?path=${encodeURIComponent(path)}`, {
|
|
801
|
+
headers: cliCore.resolveHeaders(headers)
|
|
783
802
|
});
|
|
784
803
|
const data = await res.json();
|
|
785
804
|
return data.entries;
|
|
786
805
|
}
|
|
787
806
|
async cat(serverUrl2, path, headers) {
|
|
788
|
-
const res = await this._fetch(`${serverUrl2}/api/
|
|
789
|
-
headers
|
|
807
|
+
const res = await this._fetch(`${serverUrl2}/api/qcli/fs/cat?path=${encodeURIComponent(path)}`, {
|
|
808
|
+
headers: cliCore.resolveHeaders(headers)
|
|
790
809
|
});
|
|
791
810
|
const data = await res.json();
|
|
792
811
|
return data.content;
|
|
793
812
|
}
|
|
794
813
|
async stat(serverUrl2, path, headers) {
|
|
795
|
-
const res = await this._fetch(`${serverUrl2}/api/
|
|
796
|
-
headers
|
|
814
|
+
const res = await this._fetch(`${serverUrl2}/api/qcli/fs/stat?path=${encodeURIComponent(path)}`, {
|
|
815
|
+
headers: cliCore.resolveHeaders(headers)
|
|
797
816
|
});
|
|
798
817
|
return await res.json();
|
|
799
818
|
}
|
|
800
819
|
async download(serverUrl2, path, headers, onProgress, signal) {
|
|
801
|
-
const res = await this._fetch(`${serverUrl2}/api/
|
|
802
|
-
headers,
|
|
820
|
+
const res = await this._fetch(`${serverUrl2}/api/qcli/fs/download?path=${encodeURIComponent(path)}`, {
|
|
821
|
+
headers: cliCore.resolveHeaders(headers),
|
|
803
822
|
signal
|
|
804
823
|
});
|
|
805
824
|
const contentLength = parseInt(res.headers.get("content-length") || "0", 10);
|
|
@@ -832,23 +851,23 @@ var ScpTransferService = class {
|
|
|
832
851
|
const formData = new FormData();
|
|
833
852
|
formData.append("path", remotePath);
|
|
834
853
|
formData.append("file", new Blob([content]), filename);
|
|
835
|
-
await this._fetch(`${serverUrl2}/api/
|
|
854
|
+
await this._fetch(`${serverUrl2}/api/qcli/fs/upload`, {
|
|
836
855
|
method: "POST",
|
|
837
856
|
body: formData,
|
|
838
|
-
headers
|
|
857
|
+
headers: cliCore.resolveHeaders(headers)
|
|
839
858
|
});
|
|
840
859
|
}
|
|
841
860
|
async mkdir(serverUrl2, path, headers) {
|
|
842
|
-
await this._fetch(`${serverUrl2}/api/
|
|
861
|
+
await this._fetch(`${serverUrl2}/api/qcli/fs/mkdir`, {
|
|
843
862
|
method: "POST",
|
|
844
|
-
headers: { "Content-Type": "application/json", ...headers },
|
|
863
|
+
headers: { "Content-Type": "application/json", ...cliCore.resolveHeaders(headers) },
|
|
845
864
|
body: JSON.stringify({ path })
|
|
846
865
|
});
|
|
847
866
|
}
|
|
848
867
|
async rm(serverUrl2, path, headers) {
|
|
849
|
-
await this._fetch(`${serverUrl2}/api/
|
|
868
|
+
await this._fetch(`${serverUrl2}/api/qcli/fs/rm?path=${encodeURIComponent(path)}`, {
|
|
850
869
|
method: "DELETE",
|
|
851
|
-
headers
|
|
870
|
+
headers: cliCore.resolveHeaders(headers)
|
|
852
871
|
});
|
|
853
872
|
}
|
|
854
873
|
async _fetch(url, init) {
|