A Node.js library and CLI tool for managing iCloud Drive files and directories, with support for macOS and Windows.
- Prerequisites
- Installation
- Quick Start
- API Reference
- CLI Usage
- Platform-Specific Implementations
- License
- Node.js 16 or later
- Operating System:
- macOS: Any version with iCloud Drive enabled
- Windows: Windows 10 or later with iCloud for Windows installed
- Linux: Not supported
- iCloud Drive enabled and configured
- Sufficient permissions to access iCloud directories
This tool relies on the following key dependencies:
- @oclif/core: Command line interface framework
- @inquirer/prompts: Interactive command line user interface
- minimatch: File pattern matching
Using npm:
# Install globally
npm install -g icloudy
# Install as a dependency
npm install icloudy
Using yarn:
# Install globally
yarn global add icloudy
# Install as a dependency
yarn add icloudy
Using pnpm:
# Install globally
pnpm add -g icloudy
# Install as a dependency
pnpm add icloudy
import {findICloudPaths, copyToiCloud} from 'icloudy';
// Find all iCloud paths
const paths = await findICloudPaths();
console.log(paths);
// Find specific app paths
const notesPaths = await findICloudPaths({
appName: 'Notes',
});
console.log(notesPaths);
// Copy a file to iCloud Drive root
const copyResult = await copyToiCloud('./myfile.txt');
console.log(`Copied to: ${copyResult.targetPath}`);
// Copy to specific app with options (new syntax)
const advancedCopyResult = await copyToiCloud('./documents', 'Pages', {
pattern: '*.md',
recursive: true,
overwrite: true,
});
console.log(`Copied ${advancedCopyResult.copiedFiles.length} files`);
// Copy to specific app with options (alternative syntax)
const alternativeCopyResult = await copyToiCloud('./documents', {
app: 'Pages',
pattern: '*.md',
recursive: true,
overwrite: true,
});
import {findICloudPaths} from 'icloudy';
// Find all iCloud paths
const allPaths = await findICloudPaths();
// Find specific app paths
const notesPaths = await findICloudPaths({
appName: 'Notes',
});
// Find with detailed information
const detailedPaths = await findICloudPaths({
verbose: true,
});
// Find specific path types
const rootPaths = await findICloudPaths({type: 'root'});
const docPaths = await findICloudPaths({type: 'docs'});
const photoPaths = await findICloudPaths({type: 'photos'});
const otherPaths = await findICloudPaths({type: 'other'});
interface PathInfo {
path: string; // Absolute path to the iCloud location
exists: boolean; // Whether the path exists on the file system
isAccessible: boolean; // Whether the path is accessible by the current user
score: number; // Confidence score (0-100) indicating how likely this is a valid iCloud path
metadata: {
appName?: string; // Human-readable app name (e.g., 'Notes', 'Pages')
bundleId?: string; // App bundle ID (e.g., 'com.apple.notes')
contents?: string[]; // Directory contents if available
stats?: Stats; // File system stats
source?: {
source: string; // How the path was found: 'common', 'registry', 'user_home', etc.
[key: string]: any;
};
};
}
interface SearchOptions {
appName?: string; // Filter by app name (e.g., 'Notes', 'Pages')
includeInaccessible?: boolean; // Include paths that exist but aren't accessible
minScore?: number; // Minimum confidence score (0-100)
}
// Returns Promise<PathInfo[]>
Example usage:
import {findICloudPaths} from 'icloudy';
// Find all iCloud paths
const allPaths = await findICloudPaths();
// Find paths for a specific app
const notesPaths = await findICloudPaths({appName: 'Notes'});
// Find all paths with a minimum confidence score
const reliablePaths = await findICloudPaths({minScore: 75});
{
"status": "success",
"timestamp": "2024-01-20T12:00:00Z",
"summary": {
"total": 3,
"accessible": 3,
"inaccessible": 0
},
"paths": [
{
"path": "/Users/username/Library/Mobile Documents/com~apple~CloudDocs",
"exists": true,
"isAccessible": true,
"score": 95,
"metadata": {
"appName": "iCloud Drive",
"bundleId": "com.apple.CloudDocs",
"hasICloudMarkers": true,
"contents": ["Documents", "Photos"],
"source": {
"source": "common"
}
}
},
{
"path": "/Users/username/Library/Mobile Documents/com~apple~Notes",
"exists": true,
"isAccessible": true,
"score": 90,
"metadata": {
"appName": "Notes",
"bundleId": "com.apple.Notes",
"source": {
"source": "appStorage"
}
}
}
]
}
import {copyToiCloud} from 'icloudy';
// Simple copy to iCloud Drive root
const result = await copyToiCloud('./localfile.txt');
// Copy to specific app with options (recommended syntax)
const result = await copyToiCloud('./documents', 'Notes', {
pattern: '*.md',
recursive: true,
overwrite: true,
});
// Copy to specific app with options (alternative syntax)
const result = await copyToiCloud('./documents', {
app: 'Notes',
pattern: '*.md',
recursive: true,
overwrite: true,
});
// Analyze without copying (dry run)
const result = await copyToiCloud('./project', 'Documents', {
pattern: '*.{js,ts,json}',
recursive: true,
dryRun: true,
});
// Handle copy results
if (result.success) {
console.log(`Successfully copied ${result.copiedFiles.length} files to ${result.targetPath}`);
console.log('Copied files:', result.copiedFiles);
} else {
console.error(`Failed to copy ${result.failedFiles.length} files`);
console.error(
'Errors:',
result.errors.map(err => err.message),
);
}
// Copy with interactive confirmation (CLI-like experience)
const interactiveResult = await copyToiCloud('./important-data', 'Documents', {
interactive: true,
detailed: true,
});
// Copy to iCloud Drive root with options
copyToiCloud(source: string, options?: CopyOptions): Promise<CopyResult>;
// Copy to specific app with options
copyToiCloud(source: string, target: string, options?: CopyOptions): Promise<CopyResult>;
For more advanced use cases or when you need to perform multiple operations with the same configuration:
import {FileCopier, CopyOptions} from 'icloudy';
// Create a copier instance
const copier = new FileCopier();
// Basic copying (using options object)
const result = await copier.copy({
source: './localfile.txt',
app: 'Notes',
});
// Basic copying (using parameters)
const result = await copier.copy('./localfile.txt', 'Notes');
// Analyze files without copying
const analysis = await copier.analyze({
source: './documents',
app: 'Pages',
pattern: '*.md',
recursive: true,
});
// Advanced copy options (using parameters)
const advancedResult = await copier.copy('./project', 'Documents', {
pattern: '*.{js,ts,json}',
recursive: true,
overwrite: true,
dryRun: false,
force: false,
interactive: true,
});
// Copy using options object
FileCopier.copy(options: CopyOptions): Promise<CopyResult>;
// Copy using source, target and options parameters
FileCopier.copy(source: string, target?: string, options?: CopyOptions): Promise<CopyResult>;
// Analyze files without copying
FileCopier.analyze(options: Omit<CopyOptions, 'dryRun' | 'overwrite'>): Promise<FileAnalysis>;
interface CopyOptions {
source: string; // Source file or directory path
app?: string; // Target application name
pattern?: string; // File matching pattern (e.g., "*.txt")
recursive?: boolean; // Whether to copy directories recursively
overwrite?: boolean; // Whether to overwrite existing files
dryRun?: boolean; // Analyze only without actual copying
detailed?: boolean; // Display detailed information
table?: boolean; // Display results in table format
force?: boolean; // Skip confirmation prompts
interactive?: boolean; // Interactive mode
}
interface CopyResult {
success: boolean; // Whether the operation was successful
targetPath: string; // Target path
copiedFiles: string[]; // List of copied files
failedFiles: string[]; // List of files that failed to copy
errors: Error[]; // Error information
}
interface FileAnalysis {
source: string; // Source path
targetPaths: PathInfo[]; // Target path information
filesToCopy: string[]; // List of files to copy
totalFiles: number; // Total number of files
totalSize: number; // Total file size (bytes)
}
The library uses error codes and detailed error messages to help diagnose issues:
try {
const paths = await findICloudPaths();
} catch (error) {
if (error.code === 'EACCES') {
console.error('Permission denied accessing iCloud paths');
} else if (error.code === 'ENOENT') {
console.error('iCloud Drive not found or not configured');
} else {
console.error('Error:', error.message);
}
}
Options:
-h, --help Show help information
-j, --json Output in JSON format
-n, --no-color Disable colored output
-s, --silent Suppress all output except errors
-v, --version Show version information
Find and display iCloud Drive paths on your system.
Usage: icloudy find [options] [appName]
Arguments:
appName App name to search for (optional)
Options:
-d, --detailed Show detailed information for each path
-t, --table Show results in table format (will automatically enable detailed view)
-a, --all Include all paths (including inaccessible ones)
-c, --score <n> Minimum score threshold for filtering results (default: 0)
-j, --json Output in JSON format
--no-color Disable colored output
-s, --silent Show errors only
Examples:
# Find all iCloud paths
icloudy find
# Find app-specific paths
icloudy find Notes
icloudy find "Apple Pages"
# Show detailed information
icloudy find -d
icloudy find -t # Show in table format (automatically enables detailed view)
icloudy find -j # Show all paths in JSON format
# Advanced filtering
icloudy find -i -m 50 # Include inaccessible paths with score >= 50
Copy files and directories to iCloud Drive locations.
Usage: icloudy copy <source> [options] [appName]
Arguments:
source Source path to copy from
appName Target app name (optional)
Options:
-p, --pattern <pattern> File pattern to match (default: *)
-r, --recursive Copy directories recursively
-f, --force Overwrite existing files
-d, --dry-run Show what would be copied without actually copying
-i, --interactive Enable interactive confirmation
-y, --yes Skip all confirmations
-D, --detailed Show detailed copy information
-t, --table Show results in table format (requires -D)
-j, --json Output results in JSON format
--no-color Disable colored output
-s, --silent Suppress all output except errors
Examples:
# Basic copying
icloudy copy ./localfile # Copy to iCloud Drive root
icloudy copy ./notes Notes # Copy to Notes app storage
# Advanced usage
icloudy copy ./folder -r # Recursive copy
icloudy copy ./docs -p "*.md" # Copy only markdown files
icloudy copy ./data Pages -i # Interactive mode with specific app
icloudy copy ./backup -f # Force overwrite
icloudy copy ./project -d # Dry run
icloudy copy ./files -D -t # Show detailed table output
iCloudy provides support for different operating systems to locate and interact with iCloud Drive files.
On macOS, iCloud Drive uses the following directory structure:
- Main iCloud Drive directory:
~/Library/Mobile Documents/com~apple~CloudDocs
- App-specific storage paths follow these patterns:
- Apple apps:
~/Library/Mobile Documents/com~apple~{AppName}
- Example:
~/Library/Mobile Documents/com~apple~Notes
for Apple Notes
- Example:
- Third-party apps:
~/Library/Mobile Documents/{BundleID}
where BundleID uses~
instead of.
- Example:
~/Library/Mobile Documents/com~readdle~CommonDocuments
for Documents by Readdle - Example:
~/Library/Mobile Documents/iCloud~md~obsidian
for Obsidian
- Example:
- Apple apps:
On Windows, iCloud Drive uses a different directory structure:
- Main iCloud Drive directory: Usually
C:\Users\{username}\iCloudDrive
- App-specific storage paths:
- Apple apps:
{iCloudDrive}\iCloud~com~apple~{AppName}
- Example:
C:\Users\{username}\iCloudDrive\iCloud~com~apple~Notes
- Example:
- Third-party apps:
{iCloudDrive}\iCloud~{BundleID}
with~
instead of.
- Example:
C:\Users\{username}\iCloudDrive\iCloud~com~readdle~CommonDocuments
- Example:
- Apple apps:
iCloudy automatically handles these different path formats and provides a consistent interface to access them.
Apache-2.0