LogoLogo
Developer HubGitHubContact Us
  • Welcome!
  • Olive Helps
    • Platform
      • How Olive Helps Works
      • Installation
      • Account Creation
      • Distributing Olive Helps
    • FAQs
      • General Loop FAQs
      • Loop Development FAQs
      • Olive Helps User FAQs
      • Security / IT FAQs
    • Data Security
      • User Data
      • Antivirus and Firewalls
  • Loop Development Kit
    • Your First Loop
      • Become a Loop Author
      • Creating a Loop
      • Build Your Loop
      • Local Loop Installation
      • Restarting Local Loops
    • Troubleshooting
    • Loop Security
      • Permissions
      • Environment Permissions
    • Loop Publication
      • Loop Approval Checklist
    • Loop Analytics Library
    • Examples
  • Documentation
  • Interfaces
  • Type Alias
  • Enumerations
  • Whisper Components
    • Base Attributes
    • Autocomplete
    • Box
    • Breadcrumb
    • Button
    • Chart
    • CollapseBox
    • Grid
    • Checkbox
    • Date Time
    • Divider
    • DropZone
    • Email
    • Icon
    • List Pair
    • Link
    • Pagination
    • Number
    • Markdown
    • Message
    • Password
    • Progress
    • Radio
    • Rating
    • RichTextEditor
    • Section Title
    • Select
    • Text Input
    • Telephone
    • Typography
  • APTITUDES
    • What are Aptitudes?
    • Browser
    • Clipboard
    • Config
    • Cursor
      • Screen Scaling Behavior
    • Document
    • Filesystem
    • Keyboard
    • Network
    • Process
    • Screen
    • Search
      • Index
    • System
    • UI
      • Loop UI Handlers
    • User
      • JWT
    • Vault
    • Whisper
      • Whisper Updates
      • JSX Whispers
    • Window
      • Screen Scaling Behavior
  • Release Notes
    • What's New
      • Olive Helps v0.55.0
      • Olive Helps v0.54.1
      • Olive Helps v0.53.1
      • Olive Helps v0.51.2
      • LDK v4.0.0
      • Olive Helps v0.50.3
      • Olive Helps v0.49.5
      • LDK v 3.18.0
      • Olive Helps v0.47.2
      • Olive Helps v0.46.2
      • LDK v 3.17.0
      • Olive Helps v0.45.4
      • Olive Helps v0.44.2
      • Olive Helps v0.43.1
      • Olive Helps v0.42.1
      • Olive Helps v0.41.4
      • Olive Helps v0.40.2
      • Olive Helps v0.39.4 & LDK v3.16.0
      • Olive Helps v0.38.8 & LDK v3.15.0
      • Olive Helps v0.36.5
      • Olive Helps v0.36.4
    • Archive
      • Olive Helps v0.36.3 & LDK v3.14.0
      • Olive Helps v0.34.4
      • LDK v3.13.0
      • Olive Helps v0.32.2 & LDK v3.12.0
      • Olive Helps v0.31.2 & LDK v3.11.0
      • Olive Helps v0.30.2 & LDK v3.10.0
      • Olive Helps v0.29.4
      • Olive Helps v0.29.3 & LDK v3.9.0
      • Olive Helps v0.28.3 & LDK v3.8.0
      • Olive Helps v0.27.7
      • Olive Helps v0.27.5
      • Olive Helps v.027.4
      • Olive Helps v0.27.2 & LDK v3.7.0
      • Olive Helps v0.25.3 & LDK v3.5.1
      • Olive Helps v0.24.6 & LDK v3.4.0
      • Olive Helps v0.23.2 & LDK v3.3.0
      • Olive Helps v0.22.3 & LDK v3.2.0
Powered by GitBook
On this page

Was this helpful?

  1. APTITUDES

Filesystem

The Filesystem Aptitude provides the ability to interact with files on the system (including things reading, writing, and deleting).

Each Loop is provided with their own blank "working" directory for this Aptitude, which is what relative paths resolve to. Loops are free to do anything they want to any file/directory inside of this working directory.

Loops cannot access other Loops' working directories.

This working directory persists across Loop version updates.

Copy

Copies a file from one location to another.

import { filesystem } from '@oliveai/ldk';

const SOURCE_PATH = '/var/log/system.log';
const DESTINATION_PATH = '/Users/username/system.log';

// Check to make sure the system log exists
const systemLogExists = await filesystem.exists(SOURCE_PATH);

// Copy the system log to the user folder
if (systemLogExists) {
    await filesystem.copy(SOURCE_PATH, DESTINATION_PATH);
}

dir

Returns all files in the specified directory.

import { filesystem } from '@oliveai/ldk';

// Get all files in the /var/log directory
const allLogs = await filesystem.dir('/var/log');

/*
allLogs:
[
  {
    "name": "foo.txt",
    "size": 476,
    "mode": "-rw-r--r--",
    "modTime": "2021-10-18T12:46:16.234535644-04:00",
    "isDir": false
  },
  {
    "name": "bar",
    "size": 96,
    "mode": "drwxr-xr-x",
    "modTime": "2021-09-19T05:25:54.491321266-04:00",
    "isDir": true
  },
  ...
]
*/

exists

Return true if a file or directory exists at the specified location.

import { filesystem } from '@oliveai/ldk';

// Check to make sure /var/log directory exists
const logDirExists = await filesystem.exists('/var/log');
// logDirExists === true

// Check to make sure /var/log/system.log file exists
const sysLogExists = await filesystem.exists('/var/log/system.log');
// sysLogExists === true

// Check to make sure /var/log/fakeDirectory directory exists
const fakeDirExists = await filesystem.exists('/var/log/fakeDirectory');
// fakeDirExists === false

join

Join joins an array of path elements into a single path, separating them with an OS specific Separator. Empty elements are ignored. The result is cleaned. However, if the argument list is empty or all its elements are empty, Join returns an empty string. On Windows, the result will only be a UNC path if the first non-empty element is a UNC path.

import { filesystem } from '@oliveai/ldk';

// Create path string for a local text file that works on both 
// Windows and Unix-based systems
const testDirectory = await filesystem.join(['testDirectory', 'foo.txt']);
// Windows: testDirectory == testDirectory\foo.txt
// macOS: testDirectory == testDirectory/foo.txt

listenDir

Listen for changes to the contents of the directory.

import { filesystem } from '@oliveai/ldk';

// The path of the directory where we want to listen for changes
const PATH = '/var/log';
// The callback function that runs when a change is detected
const callback = (fileEvent) => {
    // When a file or directory are added, opened, or updated:
    /*
    fileEvent:
    {
      "info": {
        "name": "foo.log",
        "size": 17,
        "mode": "-rwxr-xr-x",
        "modTime": "2021-10-27T22:14:24.596962-04:00",
        "isDir": false
      },
      "action": "Create" or "Chmod"
    }
    */
    
    // When a file or directory is renamed or removed, it will fire off 
    // the above fileEvent then another one afterward:
    /*
    fileEvent:
    {
      "action": "Rename" or "Remove",
      "name": "test.log" // old file name
    }
    */
}

const directoryListener = await filesystem.listenDir(PATH, callback);

// Cancel the listener
directoryListen.cancel();

listenFile

Listen for changes to a specific file.

import { filesystem } from '@oliveai/ldk';

// The path of the file we want to listen to for changes
const PATH = '/var/log/system.log';
// The callback function that runs when a change is detected
const callback = (fileEvent) => {
    // When the file is opened or updated:
    /*
    fileEvent:
    {
      "info": {
        "name": "system.log",
        "size": 14592,
        "mode": "-rwxr-xr-x",
        "modTime": "2021-10-27T22:31:24.215811-04:00",
        "isDir": false
      },
      "action": "Chmod"
    }
    */
    
    // When the file is renamed or removed, it will fire off 
    // the above fileEvent then another one afterward:
    /*
    fileEvent:
    {
      "action": "Rename" or "Remove",
      "name": "system.log" // old file name
    }
    */
}

const fileListener = await filesystem.listenFile(PATH, callback);

// Cancel the listener
fileListener.cancel();

makeDir

Makes a directory at the specified location.

import { filesystem } from '@oliveai/ldk';

// The path of the directory we want to create
const DESTINATION_PATH = '/var/log/backups';

// The permissions we want to give the directory, in octal format
// https://www.linode.com/docs/guides/modify-file-permissions-with-chmod/
const WRITE_MODE = 0o750

// Check to make sure the directory doesn't already exist
const directoryExists = await filesystem.exists(DESTINATION_PATH);

if (!directoryExists) {
    await filesystem.makeDir(DESTINATION_PATH, WRITE_MODE);
}

move

Moves a file from one location to another.

import { filesystem } from '@oliveai/ldk';

const SOURCE_PATH = '/var/log/system.log';
const DESTINATION_PATH = '/Users/username/system.log';

// Check to make sure the system log exists
const systemLogExists = await filesystem.exists(SOURCE_PATH);

// Move the system log to the user folder
await filesystem.move(SOURCE_PATH, DESTINATION_PATH);

openWithDefaultApplication

Opens a file using the operating system's default tool for the extension provided in the path parameter, including directories.

Limited to the following file extensions: .txt, .xls, .xlsx, .csv, .pdf, .doc, .docx, .jpg, .jpeg, .png, .apng, .gif, .tif, .tiff, .bmp, .webp, .svg, and .ico

import { filesystem } from '@oliveai/ldk';

// Open foo.txt in the loop directory
await filesystem.openWithDefaultApplication('foo.txt')

readFile

Returns the contents of the specified file.

import { filesystem, network } from '@oliveai/ldk';

// Path of the system log that we want to read
const FILE_PATH = '/var/log/system.log';

// Get the contents of the system log, returned as a Uint8Array
const encodedSysLog = await filesystem.readFile(FILE_PATH);

// Decode the contents to get the actual string value
const decodedSysLog = await network.decode(encodedSysLog);

// decodedSysLog === human readable string of system.log contents

remove

Removes a file/directory at the specified path.

import { filesystem } from '@oliveai/ldk';

// Path of foo.txt in the local loop directory
const FILE_PATH = 'foo.txt';

// Delete foo.txt
await filesystem.remove(FILE_PATH);

stat

Returns info about a specified file/directory.

import { filesystem } from '@oliveai/ldk';

const DIRECTORY_PATH = '/var/log';
const FILE_PATH = '/var/log/system.log';

const directoryInfo = await filesystem.stat(DIRECTORY_PATH);
/*
directoryInfo:
{
  "name": "log",
  "size": 1408,
  "mode": "drwxr-xr-x",
  "modTime": "2021-10-28T01:01:11.003025289-04:00",
  "isDir": true
}
*/

const fileInfo = await filesystem.stat(FILE_PATH);
/*
system.log:
{
  "name": "system.log",
  "size": 353232,
  "mode": "-rw-r-----",
  "modTime": "2021-10-28T12:29:25.305970009-04:00",
  "isDir": false
}
*/

unzip

Unzips sourced file to a specified directory.

import { filesystem } from '@oliveai/ldk';

// foo.zip is in the local loop directory, and contains bar.txt
// Unzip the contents of foo.zip to the directory "baz"
await filesystem.unzip('foo.zip', 'baz');

const unzipSuccessful = await filesystem.exists('baz/bar.txt');
// unzipSuccessful === true

workDir

Get the Loop's working directory.

import { filesystem } from '@oliveai/ldk';

// Get the full path to the loop's working directory
const loopPath = await filesystem.workDir();

// macOS: loopPath === /Users/username/Library/Application Support/Olive Helps/secureloopWork/123456-unique-loop-id
// Windows: loopPath === C:\Users\username\AppData\Roaming\Olive Helps\secureloopWork\123456-unique-loop-id

writeFile

WriteFile writes data to a file and is designed for both synchronous and asynchronous operation.

import { filesystem } from '@oliveai/ldk';

// The content we'll be putting in the file
const FILE_CONTENT = 'Some test text to put in a file';

// The path in the loop directory for the file
const DIRECTORY = 'foo';
const FILE_NAME = 'bar.txt';
const filePath = await filesystem.join([DIRECTORY, FILE_NAME]);

// The permissions we want to give the file, in octal format
// https://www.linode.com/docs/guides/modify-file-permissions-with-chmod/
const FILE_PERMISSIONS = 0o750;

// The write operations to choose from while writing the file
const { overwrite, append } = filesystem.WriteOperation;

const writeFileParams = {
    data: FILE_CONTENT,
    path: filePath,
    writeMode: FILE_PERMISSIONS,
    writeOperation: overwrite
};

await filesystem.writeFile(writeFileParams);
import { filesystem, clipboard } from '@oliveai/ldk';

const FILE_NAME = 'clipboardPastes.txt';
const baseWriteFileParams = {
    data: '',
    path: FILE_NAME,
    writeMode: 0o755,
    writeOperation: filesystem.WriteOperation.append,
};

// Include clipboard events that happen while the 
// Olive Helps window is in focus
const INCLUDE_OLIVE_HELPS_EVENTS = true;

clipboard.listen(INCLUDE_OLIVE_HELPS_EVENTS, (clipboardText) => {
    const writeFileParams = {
        ...baseWriteFileParams,
        data: clipboardText + '\n',
    };

    await filesystem.writeFile(writeFileParams);
});

Listen to directory for zip files and automatically unzip then delete zip file. This could be customized with the Dropzone component to select the exact folder to monitor for ZIP files.

import { filesystem } from '@oliveai/ldk';

// Here we're declaring the downloads folder, but this can be chosen by the
// user using the Dropzone component in a Whisper
const downloadsFolder = '/Users/username/Downloads';

filesystem.listenDir(downloadsFolder, async (fileEvent) => {
    const { action, info } = fileEvent;

    // If a file was "created" in this directory
    if (action === 'Create' && info) {
        const { name: fileName } = info;

        // If the file is a zip file, unzip it
        if (fileName.endsWith('.zip')) {
            const zipFilePath = await filesystem.join([downloadsFolder, fileName]);

            // Unzip the contents to the Downloads folder
            await filesystem.unzip(zipFilePath, downloadsFolder);

            // Delete the zip file after unzipping
            await filesystem.remove(zipFilePath);
        }
    }
});

To use the Filesystem Aptitude, use the following permissions outline in your package.json under the ldk object.

...
"ldk": {
  "permissions": {
    "filesystem": {
      "pathGlobs": [
        {
          "value": "string"
        },
        ...
      ]
    },
    ...
  }
},
...

Relative file paths can be accessed without specifying them in the permissions list.

Examples

{
  "ldk": {
    "permissions": {
      "filesystem": {
        "pathGlobs": [
          {
            // Provides access to all files in the /tmp directory that have a .txt extension.
            "value": "/tmp/*.txt"
          },
          {
            // Provides access to all directories and files under the /tmp directory.
            "value": "/tmp/**"
          },
          {
            // Provides access to all files with .txt extensions in the /tmp directory or any of its subdirectories.
            "value": "/tmp/**/*.txt"
          },
          {
            // Provides access to all files with .txt extensions in any subdirectory of /tmp.
            "value": "/tmp/*/*.txt"
          }
        ]
      }
    }
  }
}
PreviousDocumentNextKeyboard

Last updated 3 years ago

Was this helpful?

In this example, we use the to listen for you copying text to the clipboard, and automatically append it to a file in the local Loop directory. This could be useful to pair with a button/toggle in a Whisper, where this capability can be enabled before rapidly copying several items, pasted into the file, then toggle it off when finished.

Please see our page for more information.

Each value can either refer to an exact absolute path or use a wildcard. The only supported wildcards are ** and *, and can be used anywhere in the path.

Clipboard aptitude
Permissions
glob