scp-next 1.0.7 → 1.0.8

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 CHANGED
@@ -44,8 +44,7 @@ scp-next run <job> [source] [destination] [options]
44
44
  CLI commands use `<source> <destination>`. Programmatic upload and download APIs use
45
45
  `localPath` and `remotePath`.
46
46
 
47
- Destination paths follow familiar `cp`/`scp` behavior. If the destination exists as a directory or ends with a path separator, `scp-next` places the source inside that directory using the source basename.
48
- Use `--create-directories` when a destination directory may be missing.
47
+ Destination paths follow familiar `cp`/`scp` behavior. If the destination exists as a directory or ends with a path separator, `scp-next` places the source inside that directory using the source basename. Missing destination directories are created by default.
49
48
 
50
49
  ## Upload Examples
51
50
 
@@ -54,8 +53,7 @@ scp-next upload ./dist /var/www/example \
54
53
  --host example.com \
55
54
  --username deploy \
56
55
  --private-key-file ~/.ssh/id_ed25519 \
57
- --recursive \
58
- --create-directories
56
+ --recursive
59
57
  ```
60
58
 
61
59
  Password authentication:
@@ -77,8 +75,7 @@ Prefer `SCP_NEXT_PASSWORD`, SSH agents, or protected private-key files for share
77
75
  scp-next download /var/log/example.log ./logs/example.log \
78
76
  --host example.com \
79
77
  --username deploy \
80
- --private-key-file ~/.ssh/id_ed25519 \
81
- --create-directories
78
+ --private-key-file ~/.ssh/id_ed25519
82
79
  ```
83
80
 
84
81
  ## CLI Options
@@ -96,7 +93,8 @@ scp-next download /var/log/example.log ./logs/example.log \
96
93
  | `--profile <name>` | Named server profile from the configuration file. |
97
94
  | `--recursive` | Transfer directories recursively. |
98
95
  | `--overwrite` | Allow replacing existing destination files. |
99
- | `--create-directories` | Create missing destination directories when supported. |
96
+ | `--create-directories` | Create missing destination directories. Enabled by default. |
97
+ | `--no-create-directories` | Disable automatic destination directory creation. |
100
98
  | `--dry-run` | Resolve and validate the operation without connecting or transferring. |
101
99
  | `--timeout <milliseconds>` | Connection and operation timeout in milliseconds. |
102
100
  | `--verbose` | Print non-sensitive diagnostic details. |
package/dist/cli/index.js CHANGED
@@ -564,7 +564,7 @@ async function validateDownloadOptions(options) {
564
564
  }
565
565
  assertRemotePath(options.remotePath, "remotePath");
566
566
  validateTimeout(options.timeout);
567
- await assertDownloadDestination(options.localPath, options.createDirectories);
567
+ await assertDownloadDestination(options.localPath, options.createDirectories ?? true);
568
568
  if (!options.dryRun) {
569
569
  await validateServerOptions(options);
570
570
  }
@@ -580,6 +580,9 @@ function percentage(transferredBytes, totalBytes) {
580
580
  function mergeOptions(serverOptions, transferOptions) {
581
581
  return { ...serverOptions, ...transferOptions ?? {} };
582
582
  }
583
+ function shouldCreateDirectories(options) {
584
+ return options.createDirectories ?? true;
585
+ }
583
586
  function hasTrailingPathSeparator(inputPath) {
584
587
  return /[\\/]$/.test(inputPath);
585
588
  }
@@ -721,7 +724,7 @@ var ScpNextClientImpl = class {
721
724
  const remoteKind = await this.transport.exists(remotePath);
722
725
  const isDirectoryLikeDestination = remoteKind === "d" || remotePath.endsWith("/");
723
726
  if (!isDirectoryLikeDestination) {
724
- await this.ensureRemoteParent(remotePath, options.createDirectories);
727
+ await this.ensureRemoteParent(remotePath, shouldCreateDirectories(options));
725
728
  await this.assertRemoteOverwrite(remotePath, options.overwrite);
726
729
  return remotePath;
727
730
  }
@@ -732,7 +735,7 @@ var ScpNextClientImpl = class {
732
735
  }
733
736
  const remoteDirectory = remotePath.replace(/\/+$/g, "") || "/";
734
737
  if (!remoteKind) {
735
- if (!options.createDirectories) {
738
+ if (!shouldCreateDirectories(options)) {
736
739
  throw new TransferError(`Remote destination directory does not exist: ${remoteDirectory}`, {
737
740
  context: { remotePath }
738
741
  });
@@ -758,7 +761,7 @@ var ScpNextClientImpl = class {
758
761
  if (isDirectoryLikeDestination) {
759
762
  const remoteDirectory = trimmedRemoteDirectory(remotePath);
760
763
  if (!remoteKind) {
761
- if (!options.createDirectories) {
764
+ if (!shouldCreateDirectories(options)) {
762
765
  throw new TransferError(`Remote destination directory does not exist: ${remoteDirectory}`, {
763
766
  context: { remotePath }
764
767
  });
@@ -770,7 +773,7 @@ var ScpNextClientImpl = class {
770
773
  return destinationRoot;
771
774
  }
772
775
  if (!remoteKind) {
773
- if (!options.createDirectories) {
776
+ if (!shouldCreateDirectories(options)) {
774
777
  throw new TransferError(`Remote destination directory does not exist: ${remotePath}`, {
775
778
  context: { remotePath }
776
779
  });
@@ -799,7 +802,7 @@ var ScpNextClientImpl = class {
799
802
  async downloadSingleFile(options, remotePath) {
800
803
  const localPath = await this.resolveLocalDestinationForRemoteFile(options, remotePath);
801
804
  await this.assertLocalOverwrite(localPath, options.overwrite);
802
- if (options.createDirectories) {
805
+ if (shouldCreateDirectories(options)) {
803
806
  await mkdir2(path4.dirname(localPath), { recursive: true });
804
807
  }
805
808
  await this.transport.downloadFile(remotePath, localPath, (step) => {
@@ -821,7 +824,7 @@ var ScpNextClientImpl = class {
821
824
  const totalBytes = files.reduce((sum, file) => sum + file.size, 0);
822
825
  let completedBytes = 0;
823
826
  let completedFiles = 0;
824
- await ensureLocalDirectory(localRoot, Boolean(options.createDirectories));
827
+ await ensureLocalDirectory(localRoot, shouldCreateDirectories(options));
825
828
  for (const file of files) {
826
829
  const localFile = path4.join(localRoot, ...file.relativePath.split("/"));
827
830
  await this.assertLocalOverwrite(localFile, options.overwrite);
@@ -851,7 +854,7 @@ var ScpNextClientImpl = class {
851
854
  return localDestination;
852
855
  }
853
856
  if (!await isExistingLocalDirectory(localDestination)) {
854
- if (!options.createDirectories) {
857
+ if (!shouldCreateDirectories(options)) {
855
858
  throw new TransferError(`Local destination directory does not exist: ${localDestination}`, {
856
859
  context: { localPath: options.localPath }
857
860
  });
@@ -867,7 +870,7 @@ var ScpNextClientImpl = class {
867
870
  return localDestination;
868
871
  }
869
872
  if (!await isExistingLocalDirectory(localDestination)) {
870
- if (!options.createDirectories) {
873
+ if (!shouldCreateDirectories(options)) {
871
874
  throw new TransferError(`Local destination directory does not exist: ${localDestination}`, {
872
875
  context: { localPath: options.localPath }
873
876
  });
@@ -1133,7 +1136,7 @@ var DEFAULT_TRANSFER = {
1133
1136
  port: 22,
1134
1137
  recursive: false,
1135
1138
  overwrite: false,
1136
- createDirectories: false,
1139
+ createDirectories: true,
1137
1140
  dryRun: false
1138
1141
  };
1139
1142
  function assignDefined(target, source) {
@@ -1323,6 +1326,7 @@ function addTransferOptions(command) {
1323
1326
  command.option("--recursive", "Transfer directories recursively");
1324
1327
  command.option("--overwrite", "Overwrite existing destination files");
1325
1328
  command.option("--create-directories", "Create missing destination directories");
1329
+ command.option("--no-create-directories", "Do not create missing destination directories");
1326
1330
  command.option("--dry-run", "Resolve and validate without connecting or transferring");
1327
1331
  command.addOption(new Option("--timeout <milliseconds>", "Connection/operation timeout").argParser(parseInteger2));
1328
1332
  command.option("--verbose", "Print verbose diagnostic output");