Files
openclaw-backups/skills/apple-shortcuts/scripts/generate.py
2026-02-17 15:50:53 +00:00

343 lines
12 KiB
Python

#!/usr/bin/env python3
"""
Apple Shortcuts Generator
Generates .shortcut files compatible with iOS/macOS Shortcuts app
"""
import json
import sys
import argparse
import base64
import plistlib
import uuid
from pathlib import Path
from datetime import datetime
TEMPLATES = {
"voice-to-notion": {
"name": "Voice to Notion",
"description": "Record voice, transcribe, and add to Notion inbox",
"actions": [
{
"WFWorkflowActionIdentifier": "is.workflow.actions.recordaudio",
"WFWorkflowActionParameters": {}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.transcribeaudio",
"WFWorkflowActionParameters": {}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.gettext",
"WFWorkflowActionParameters": {
"WFTextActionText": "Add to Notion Inbox:"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.openapp",
"WFWorkflowActionParameters": {
"WFAppIdentifier": "com.philipyoungg.notione"
}
}
]
},
"expense-logger": {
"name": "Quick Expense",
"description": "Log expense to Notion database",
"actions": [
{
"WFWorkflowActionIdentifier": "is.workflow.actions.ask",
"WFWorkflowActionParameters": {
"WFAskActionPrompt": "Amount?",
"WFAskActionAnswerType": "Number"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.choosefromlist",
"WFWorkflowActionParameters": {
"WFChooseFromListActionPrompt": "Category?",
"WFChooseFromListActionItems": ["Food", "Transport", "Entertainment", "Shopping", "Bills"]
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.gettext",
"WFWorkflowActionParameters": {
"WFTextActionText": {
"Value": {
"string": "Logged: $amount$ for $category$ on $date$"
},
"WFSerializationType": "WFTextTokenString"
}
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
"WFWorkflowActionParameters": {
"WFURLActionURL": "https://t.me/clawdbot?start=expense_"
}
}
]
},
"ha-scene": {
"name": "Home Assistant Scene",
"description": "Trigger Home Assistant scene",
"actions": [
{
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
"WFWorkflowActionParameters": {
"WFURLActionURL": "https://t.me/clawdbot?start=ha_scene_"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.showresult",
"WFWorkflowActionParameters": {
"Text": "Scene activated!"
}
}
]
},
"morning-briefing": {
"name": "Trigger Morning Briefing",
"description": "Manually trigger your Morning Intelligence Briefing",
"actions": [
{
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
"WFWorkflowActionParameters": {
"WFURLActionURL": "https://t.me/clawdbot?start=morning_briefing_now"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.showresult",
"WFWorkflowActionParameters": {
"Text": "Morning briefing requested! Check Telegram in a moment."
}
}
]
},
"send-to-openclaw": {
"name": "Send to OpenClaw",
"description": "Send text, clipboard, or input to OpenClaw",
"actions": [
{
"WFWorkflowActionIdentifier": "is.workflow.actions.gettext",
"WFWorkflowActionParameters": {
"WFTextActionText": {
"Value": {
"attachmentsByRange": {
"{0, 1}": {
"Type": "Clipboard",
"Aggrandizements": []
}
},
"string": "$0"
},
"WFSerializationType": "WFTextTokenString"
}
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.urlencode",
"WFWorkflowActionParameters": {}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
"WFWorkflowActionParameters": {
"WFURLActionURL": {
"Value": {
"string": "https://t.me/clawdbot?start=shortcut_",
"attachmentsByRange": {}
},
"WFSerializationType": "WFTextTokenString"
}
}
}
]
},
"quick-task": {
"name": "Quick Task to Notion",
"description": "Add a quick task to your Work To-do list",
"actions": [
{
"WFWorkflowActionIdentifier": "is.workflow.actions.ask",
"WFWorkflowActionParameters": {
"WFAskActionPrompt": "Task name?"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.choosefromlist",
"WFWorkflowActionParameters": {
"WFChooseFromListActionPrompt": "Priority?",
"WFChooseFromListActionItems": ["High", "Medium", "Low"]
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
"WFWorkflowActionParameters": {
"WFURLActionURL": "https://t.me/clawdbot?start=task_"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.showresult",
"WFWorkflowActionParameters": {
"Text": "Task sent to OpenClaw!"
}
}
]
},
"log-to-notion": {
"name": "Log to Notion",
"description": "Quick log entry to Notion journal/daily notes",
"actions": [
{
"WFWorkflowActionIdentifier": "is.workflow.actions.ask",
"WFWorkflowActionParameters": {
"WFAskActionPrompt": "What happened?"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.getcurrentdatetime",
"WFWorkflowActionParameters": {
"WFCurrentDateFormat": "Short"
}
},
{
"WFWorkflowActionIdentifier": "is.workflow.actions.openurl",
"WFWorkflowActionParameters": {
"WFURLActionURL": "https://t.me/clawdbot?start=log_"
}
}
]
}
}
def create_shortcut_json(name, actions, description=""):
"""Create the JSON structure for a .shortcut file"""
shortcut = {
"WFWorkflowClientVersion": "1092.0.2",
"WFWorkflowClientRelease": "4.0",
"WFWorkflowMinimumClientVersion": 900,
"WFWorkflowMinimumClientVersionString": "900",
"WFWorkflowIcon": {
"WFWorkflowIconStartColor": 4292093695,
"WFWorkflowIconGlyphNumber": 61456
},
"WFWorkflowImportQuestions": [],
"WFWorkflowTypes": ["NCWidget", "WatchKit"],
"WFWorkflowInputContentItemClasses": [
"WFAppStoreAppContentItem",
"WFArticleContentItem",
"WFContactContentItem",
"WFDateContentItem",
"WFEmailAddressContentItem",
"WFGenericFileContentItem",
"WFImageContentItem",
"WFiTunesProductContentItem",
"WFLocationContentItem",
"WFDCMapsLinkContentItem",
"WFAVAssetContentItem",
"WFPDFContentItem",
"WFPhoneNumberContentItem",
"WFRichTextContentItem",
"WFSafariWebPageContentItem",
"WFStringContentItem",
"WFURLContentItem"
],
"WFWorkflowActions": actions,
"WFWorkflowName": name
}
return shortcut
def generate_shortcut_file(template_name, output_dir="~/Downloads", custom_name=None):
"""Generate a .shortcut file from template"""
if template_name not in TEMPLATES:
print(f"❌ Template '{template_name}' not found!")
print(f"Available: {', '.join(TEMPLATES.keys())}")
return None
template = TEMPLATES[template_name]
name = custom_name or template["name"]
shortcut_data = create_shortcut_json(name, template["actions"], template["description"])
# Create output path
output_path = Path(output_dir).expanduser() / f"{name.replace(' ', '_')}.shortcut"
# Write as plist (binary format that Shortcuts app expects)
with open(output_path, 'wb') as f:
plistlib.dump(shortcut_data, f)
print(f"✅ Generated: {output_path}")
print(f" Description: {template['description']}")
print(f" Actions: {len(template['actions'])}")
print(f"\n📱 To install:")
print(f" 1. AirDrop to your iPhone/Mac, or")
print(f" 2. Open in Files app")
print(f" 3. Tap 'Add Shortcut'")
return output_path
def list_templates():
"""List all available templates"""
print("📋 Available Shortcut Templates:")
print("=" * 50)
for key, template in TEMPLATES.items():
print(f"\n🔹 {key}")
print(f" Name: {template['name']}")
print(f" Description: {template['description']}")
print(f" Actions: {len(template['actions'])}")
def generate_custom_shortcut(description, output_dir="~/Downloads"):
"""Generate a custom shortcut based on description"""
print(f"🎯 Generating custom shortcut...")
print(f" Description: {description}")
print()
print("⚠️ Custom shortcut generation requires AI processing.")
print(" In a full implementation, this would:")
print(" 1. Parse your description")
print(" 2. Generate appropriate Shortcuts actions")
print(" 3. Output a working .shortcut file")
print()
print(" For now, use --template with one of the pre-built options!")
print()
list_templates()
def main():
parser = argparse.ArgumentParser(description="Generate Apple Shortcuts (.shortcut files)")
parser.add_argument("--template", "-t", help="Template name to use")
parser.add_argument("--list", "-l", action="store_true", help="List available templates")
parser.add_argument("--output", "-o", default="~/Downloads", help="Output directory")
parser.add_argument("--name", "-n", help="Custom name for the shortcut")
parser.add_argument("--custom", "-c", help="Custom description for AI-generated shortcut")
parser.add_argument("--scene", "-s", help="Scene name (for ha-scene template)")
args = parser.parse_args()
if args.list:
list_templates()
return
if args.custom:
generate_custom_shortcut(args.custom, args.output)
return
if args.template:
# Handle scene parameter for ha-scene template
custom_name = args.name
if args.template == "ha-scene" and args.scene:
custom_name = f"Scene: {args.scene}"
generate_shortcut_file(args.template, args.output, custom_name)
return
# No arguments - show help
parser.print_help()
print("\n")
list_templates()
if __name__ == "__main__":
main()