SuperAPI AI Directory

lovstudio-finder-action

General & other

View repository

Updated 10-16 00:01

About this skill

finder-action — Mac Finder context menu action generator

Generate Finder context menu actions based on the user's description, automatically determining the mode:

Scenario Mode Technical solution
Right-clickfile/folder Quick Action Automator workflow
Right-clickblank space Finder Extension Swift + xcodegen

Parameter format

<动作名称> [触发描述]

Example:

  • pdf2png .pdf 将PDF所有页面纵向拼接成一张PNG → Quick Action
  • 新建md文件 在空白处右键创建markdown文件 → Finder Extension

Mode determination

Keyword hit → Finder Extension mode:

  • Mentions "blank space", "background", "directory background", "new file", "blank space", "background"
  • The action can be triggered without selecting a file

Other cases → Quick Action mode


Mode A: Quick Action(Automator workflow)

Step 1: Analyze requirements

Collect (use AskUserQuestion when missing):

  • Action name: display name in the context menu
  • Trigger file types:.pdf、.md、.jpg , etc.
  • Core command: what to do with which tool

Step 2: Check dependencies

which <所需工具>

If it does not exist, prompt brew install <tool>。

Step 3: Generate shell script

#!/bin/bash
for f in "$@"; do
  [[ "$f" == *.<ext> ]] || continue
  output="${f%.<ext>}.<out_ext>"
  <具体命令> "$f" -o "$output"
done
  • Use absolute paths for tool paths (the Quick Action environment does not have $PATH)
  • "$@" receive file parameters (inputMethod=1)

Step 4: Create Automator workflow

Create ~/Library/Services/<动作名称>.workflow/Contents/document.wflow。

See template at references/automator-template.xml。

Key configuration:

  • inputMethod: 1
  • serviceInputTypeIdentifier: com.apple.Automator.fileSystemObject
  • workflowTypeIdentifier: com.apple.Automator.servicesMenu

Step 5: Verify registration

plutil -lint ~/Library/Services/<动作名称>.workflow/Contents/document.wflow
/System/Library/CoreServices/pbs -update
killall Finder

Step 6: Automator save (critical)

open -a Automator ~/Library/Services/<动作名称>.workflow

It must be saved once with Cmd+S in Automator before it is officially registered.


Mode B: Finder Sync Extension(Swift app)

Step 1: Check toolchain

which xcodegen && which xcodebuild

If xcodegen is missing, brew install xcodegen。

Step 2: Create project structure

<ProjectName>/
├── project.yml
├── <ProjectName>/
│   └── AppDelegate.swift
└── FinderExtension/
    └── FinderSync.swift

Step 3: Generate project.yml

See template at references/xcodegen-template.yml. Replace APP_NAME and BUNDLE_ID。

Key points:

  • Host App: LSUIElement: true(no Dock icon)
  • Extension: NSExtensionPointIdentifier: com.apple.FinderSync
  • Signing: CODE_SIGN_IDENTITY: "-"(ad-hoc)
  • Sandbox must be enabled(app-sandbox: true), otherwise the extension will not be loaded by the system
  • File writes must use temporary-exception.files.absolute-path.read-write: [/],files.user-selected.read-write is invalid

Step 4: Generate AppDelegate.swift

import Cocoa

@main
class AppDelegate: NSObject, NSApplicationDelegate {
    func applicationDidFinishLaunching(_ notification: Notification) {}
}

Step 5: Generate FinderSync.swift

See template at references/finder-sync-template.swift。

Core APIs:

  • FIFinderSyncController.default().directoryURLs = [URL(fileURLWithPath: "/")] — monitor all directories
  • menu(for: .contextualMenuForContainer) — blank-space context menu
  • FIFinderSyncController.default().targetedURL() — get the current directory

Common action patterns:

  • Create file:FileManager.default.createFile + auto-incrementing filename
  • Open terminal: AppleScript controls iTerm2/Terminal (see references/applescript-iterm.swift)
  • Execute script:Process() launch shell command

AppleScript automationneeds to be added in entitlements:

com.apple.security.automation.apple-events: true

Step 6: Build and install

xcodegen generate
xcodebuild -project APP_NAME.xcodeproj -scheme APP_NAME -configuration Debug build
cp -R ~/Library/Developer/Xcode/DerivedData/APP_NAME-*/Build/Products/Debug/APP_NAME.app /Applications/
open /Applications/APP_NAME.app
pluginkit -e use -i BUNDLE_ID.FinderExtension

Step 7: Verify

pluginkit -m -i BUNDLE_ID.FinderExtension

If it does not appear, guide:System Settings → General → Login Items & Extensions → added extensions → check it.

Sandbox limitations and Helper App solution

The sandbox restrictions of Finder Sync Extension are very strict:

Operation Allowed Description
Write to /tmp ❌ Even adding temporary-exception is blocked
Process() child process ❌ Unable to launch external commands
NSAppleScript ❌ Unable to control other apps
NSWorkspace.open(file) ❌ Unable to open files/directories
NSWorkspace.open(app) ✅ Can open apps
NSPasteboard ✅ Can read and write the clipboard

Recommended solution: Create a non-sandboxed Helper App. The Extension puts the command on the clipboard and then opens the Helper App, which performs the actual operation.

Helper App example

mkdir -p "/Applications/OpenCCHelper.app/Contents/MacOS"
cat > "/Applications/OpenCCHelper.app/Contents/Info.plist" << 'EOF'
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>CFBundleExecutable</key><string>run.sh</string>
    <key>CFBundleIdentifier</key><string>com.lovstudio.OpenCCHelper</string>
    <key>LSUIElement</key><true/>
</dict>
</plist>
EOF

cat > "/Applications/OpenCCHelper.app/Contents/MacOS/run.sh" << 'EOF'
#!/bin/bash
CMD=$(pbpaste)
osascript << APPLESCRIPT
tell application "iTerm"
    activate
    tell current window
        create tab with default profile
        tell current session
            write text "$CMD"
        end tell
    end tell
end tell
APPLESCRIPT
EOF
chmod +x "/Applications/OpenCCHelper.app/Contents/MacOS/run.sh"

Calling from the Extension:

let command = "cd '\(targetPath)' && claude"
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(command, forType: .string)
NSWorkspace.shared.open(URL(fileURLWithPath: "/Applications/OpenCCHelper.app"))

Other known limitations

  • Bundle ID cannot contain underscores: Use hyphens or camel case (OpenCC instead of open_cc)
  • NSHomeDirectory() returns the container path: In the sandbox it returns ~/Library/Containers/<bundle-id>/Data/, and monitored directories must hard-code the real path
  • NSMenuItem must have target set:item.target = self, otherwise the action will not be triggered
  • The position of the Finder Extension menu item is determined by the system and cannot be placed before "New Folder"
  • The Quick Action environment does not have $PATH, and tool paths must use absolute paths
  • The Automator workflow must be opened and saved in Automator to be registered
  • The Extension uses ad-hoc signing and is limited to use on this machine