scpl-updated-mcp-server 1.0.4 → 1.0.6

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.
Files changed (3) hide show
  1. package/SCPL_REFERENCE.md +504 -0
  2. package/index.js +277 -353
  3. package/package.json +6 -1
@@ -0,0 +1,504 @@
1
+ # ScPL Language Reference
2
+
3
+ ScPL (Shortcut Programming Language) lets you write Apple Shortcuts as text code instead of dragging blocks.
4
+
5
+ ## Basic Syntax
6
+
7
+ ```scpl
8
+ ActionName "argument1" "argument2"
9
+ ActionName argument=value anotherArg=value
10
+ ```
11
+
12
+ ## Variables
13
+
14
+ Three types with `type:name` syntax:
15
+
16
+ | Type | Syntax | Description |
17
+ |------|--------|-------------|
18
+ | Named | `v:MyVar` | Set with SetVariable |
19
+ | Magic | `mv:MyVar` | Auto-created with `->` arrow |
20
+ | Special | `s:Name` | Built-in system variables |
21
+
22
+ ### Special Variables
23
+ - `s:ShortcutInput` - Input to the shortcut
24
+ - `s:Clipboard` - Current clipboard contents
25
+ - `s:CurrentDate` - Current date/time
26
+ - `s:AskWhenRun` - Prompt user at runtime
27
+ - `s:ActionInput` - Input to current action
28
+
29
+ ### Setting Variables
30
+
31
+ ```scpl
32
+ # Named variable (creates SetVariable action)
33
+ Text "Hello" -> v:MyText
34
+ # or
35
+ SetVariable v:MyText
36
+
37
+ # Magic variable (no action created, just reference)
38
+ Text "Hello" -> mv:MyMagic
39
+
40
+ # Pre-assignment style
41
+ mv:Result = Text "Hello"
42
+ ```
43
+
44
+ ### Using Variables in Text
45
+
46
+ ```scpl
47
+ Text "The value is \(v:MyVariable)"
48
+ Text "Clipboard: \(s:Clipboard)"
49
+ ```
50
+
51
+ ## Flow Control
52
+
53
+ ### If/Otherwise/End If
54
+
55
+ ```scpl
56
+ Text "test"
57
+ If Equals "test"
58
+ ShowResult "Match!"
59
+ Otherwise
60
+ ShowResult "No match"
61
+ End If
62
+ ```
63
+
64
+ ### Repeat
65
+
66
+ ```scpl
67
+ Repeat 5
68
+ ShowResult "Loop iteration"
69
+ End Repeat
70
+ ```
71
+
72
+ ### Repeat with Each
73
+
74
+ ```scpl
75
+ RepeatWithEach [item1, item2, item3]
76
+ ShowResult "Processing: \(mv:RepeatItem)"
77
+ End RepeatWithEach
78
+ ```
79
+
80
+ ### Choose from Menu
81
+
82
+ ```scpl
83
+ ChooseFromMenu "Pick one" ["Option A", "Option B"]
84
+ Case "Option A"
85
+ ShowResult "You picked A"
86
+ Case "Option B"
87
+ ShowResult "You picked B"
88
+ End Menu
89
+ ```
90
+
91
+ ## Field Types
92
+
93
+ ### Text Fields
94
+ ```scpl
95
+ Text "Single line"
96
+ Text
97
+ | Multiline text
98
+ | Second line
99
+ | With variable: \(v:Name)
100
+ ```
101
+
102
+ ### Numbers
103
+ ```scpl
104
+ Number 42
105
+ Number 3.14
106
+ Number -100
107
+ ```
108
+
109
+ ### Booleans
110
+ ```scpl
111
+ SetWifi true
112
+ SetBluetooth false
113
+ ```
114
+
115
+ ### Lists
116
+ ```scpl
117
+ List ["item1", "item2", "item3"]
118
+ # or
119
+ List
120
+ | Item 1
121
+ | Item 2
122
+ ```
123
+
124
+ ### Dictionaries
125
+ ```scpl
126
+ Dictionary {
127
+ key: "value"
128
+ number: 42
129
+ nested: {inner: "data"}
130
+ }
131
+ # Quotes and commas optional
132
+ ```
133
+
134
+ ## Variable Aggrandizements
135
+
136
+ Access properties of variables:
137
+
138
+ ```scpl
139
+ # Get dictionary key
140
+ v:MyDict{as:Dictionary,key:myKey}
141
+ # Shorthand
142
+ v:MyDict:myKey
143
+
144
+ # Get property
145
+ v:Contact{as:Contact,get:Email}
146
+ ```
147
+
148
+ ## Actions Inside Actions
149
+
150
+ Inline actions in parentheses:
151
+
152
+ ```scpl
153
+ Text "Number is \(Number 42)"
154
+ If Equals (Text "compare value")
155
+ ShowResult "Match"
156
+ End If
157
+ ```
158
+
159
+ ## Comments
160
+
161
+ ```scpl
162
+ # This is a comment
163
+ // Also a comment
164
+ -- Also works
165
+ ```
166
+
167
+ ---
168
+
169
+ # Common Actions
170
+
171
+ ## Text & Display
172
+
173
+ ```scpl
174
+ Text "Your text here"
175
+ ShowResult "Display this"
176
+ ShowAlert title="Title" message="Body text"
177
+ ShowNotification title="Hey" body="Message"
178
+ ```
179
+
180
+ ## Clipboard
181
+
182
+ ```scpl
183
+ GetClipboard
184
+ SetClipboard "New content"
185
+ # or with variable
186
+ Text "Copy this" -> mv:Content
187
+ SetClipboard mv:Content
188
+ ```
189
+
190
+ ## Variables
191
+
192
+ ```scpl
193
+ SetVariable v:Name
194
+ GetVariable v:Name
195
+ AddToVariable v:List
196
+ ```
197
+
198
+ ## Lists & Dictionaries
199
+
200
+ ```scpl
201
+ List ["a", "b", "c"]
202
+ GetItemFromList "First Item"
203
+ GetItemFromList "Last Item"
204
+ GetItemFromList "Random Item"
205
+ Count "Items"
206
+
207
+ Dictionary {key: "value"}
208
+ GetDictionaryValue key="mykey"
209
+ SetDictionaryValue key="mykey" value="newvalue"
210
+ ```
211
+
212
+ ## Math
213
+
214
+ ```scpl
215
+ Number 10
216
+ Calculate "+" 5
217
+ Calculate "*" 2
218
+ Calculate "/" 4
219
+ RoundNumber "Normal"
220
+ RandomNumber min=1 max=100
221
+ ```
222
+
223
+ ## Dates
224
+
225
+ ```scpl
226
+ Date "tomorrow at 9am"
227
+ FormatDate "short"
228
+ AdjustDate "1 week"
229
+ GetTimeBetweenDates unit="Days"
230
+ ```
231
+
232
+ ## Files
233
+
234
+ ```scpl
235
+ GetFile service="iCloud Drive" filepath="/path/to/file"
236
+ SaveFile destinationpath="/save/here"
237
+ GetFolderContents
238
+ DeleteFiles immediately=true
239
+ ```
240
+
241
+ ## Web
242
+
243
+ ```scpl
244
+ URL "https://example.com"
245
+ GetContentsOfURL
246
+ ExpandURL
247
+ GetComponentOfURL component="Host"
248
+ ```
249
+
250
+ ---
251
+
252
+ # macOS Tahoe Actions (New)
253
+
254
+ ## Apple Intelligence (Apple Silicon only)
255
+
256
+ ```scpl
257
+ # Ask AI model
258
+ AskLLM model="Apple Intelligence" prompt="Summarize this text"
259
+ AskLLM model="ChatGPT" prompt="Explain quantum computing"
260
+
261
+ # Image generation
262
+ GenerateImage prompt="A sunset over mountains" style="Illustration"
263
+ ```
264
+
265
+ ## AI Assistants
266
+
267
+ ```scpl
268
+ # ChatGPT (requires app)
269
+ AskChatGPT prompt="Help me write an email"
270
+ OpenChatGPTVoiceMode
271
+
272
+ # Claude (requires app)
273
+ AskClaude message="Analyze this code"
274
+ ```
275
+
276
+ ## Shell Scripts
277
+
278
+ ```scpl
279
+ # Bash script
280
+ RunShellScript shell="/bin/bash" script="echo Hello World"
281
+
282
+ # Zsh with input
283
+ GetClipboard
284
+ RunShellScript shell="/bin/zsh" script="cat | wc -w"
285
+
286
+ # AppleScript
287
+ RunAppleScript script="display dialog \"Hello!\""
288
+
289
+ # JavaScript for Automation
290
+ RunJavaScriptForAutomation script="Application('Finder').selection()"
291
+ ```
292
+
293
+ ## File Operations
294
+
295
+ ```scpl
296
+ # Get file by path
297
+ File path="~/Documents/myfile.txt"
298
+
299
+ # Rename
300
+ RenameFile name="newname.txt"
301
+
302
+ # Move
303
+ MoveFile destination="~/Desktop/"
304
+
305
+ # Reveal in Finder
306
+ RevealInFinder
307
+
308
+ # Select file (prompt)
309
+ SelectFile
310
+
311
+ # Get folder contents
312
+ GetFolderContents path="~/Documents"
313
+
314
+ # Get Finder selection
315
+ GetSelectedFiles
316
+ ```
317
+
318
+ ## System
319
+
320
+ ```scpl
321
+ # Dark/Light mode
322
+ SetAppearance "Dark"
323
+ SetAppearance "Light"
324
+
325
+ # Screenshots
326
+ TakeScreenshot
327
+
328
+ # Lock screen
329
+ LockScreen
330
+
331
+ # On-screen OCR
332
+ GetOnScreenContent
333
+ ```
334
+
335
+ ## Clock & Timers
336
+
337
+ ```scpl
338
+ StartStopwatch
339
+ StopStopwatch
340
+ CreateAlarm time="7:00 AM" label="Wake up"
341
+ StartTimer minutes=25
342
+ ```
343
+
344
+ ## Voice Memos
345
+
346
+ ```scpl
347
+ CreateRecording
348
+ PlayRecording
349
+ ```
350
+
351
+ ---
352
+
353
+ # Complete Workflow Examples
354
+
355
+ ## Morning Routine
356
+
357
+ ```scpl
358
+ # Turn off dark mode
359
+ SetAppearance "Light"
360
+
361
+ # Check weather
362
+ GetCurrentWeather -> mv:Weather
363
+ Text "Good morning! Today's weather: \(mv:Weather)"
364
+ ShowNotification title="Morning" body=mv:Text
365
+
366
+ # Open calendar
367
+ OpenApp "Calendar"
368
+ ```
369
+
370
+ ## Clipboard AI Enhancement
371
+
372
+ ```scpl
373
+ GetClipboard -> mv:Original
374
+ AskLLM model="Apple Intelligence" prompt="Improve this text for clarity: \(mv:Original)"
375
+ SetClipboard
376
+ ShowAlert title="Done" message="Improved text copied!"
377
+ ```
378
+
379
+ ## Pomodoro Timer with Logging
380
+
381
+ ```scpl
382
+ # Start work session
383
+ ShowNotification title="Pomodoro" body="25 minute focus session started"
384
+ StartTimer minutes=25
385
+
386
+ # Log session
387
+ Date -> mv:StartTime
388
+ Text "Work session started at \(mv:StartTime)" -> mv:Log
389
+ AppendToFile path="~/Documents/pomodoro-log.txt" text=mv:Log
390
+ ```
391
+
392
+ ## Screenshot with AI Description
393
+
394
+ ```scpl
395
+ TakeScreenshot -> mv:Screenshot
396
+ AskLLM model="Apple Intelligence" prompt="Describe what's in this image"
397
+ SetVariable v:Description
398
+
399
+ # Save with description
400
+ Text "Screenshot: \(v:Description)"
401
+ ShowResult
402
+ ```
403
+
404
+ ## DevOps Status Check
405
+
406
+ ```scpl
407
+ RunShellScript shell="/bin/zsh" script="git status --short" -> mv:GitStatus
408
+ RunShellScript shell="/bin/zsh" script="docker ps --format 'table {{.Names}}\t{{.Status}}'" -> mv:Docker
409
+
410
+ Text
411
+ | Git Status:
412
+ | \(mv:GitStatus)
413
+ |
414
+ | Docker Containers:
415
+ | \(mv:Docker)
416
+
417
+ ShowResult
418
+ ```
419
+
420
+ ## File Organizer
421
+
422
+ ```scpl
423
+ GetSelectedFiles -> mv:Files
424
+ RepeatWithEach mv:Files
425
+ GetDetailsOfFiles detail="File Extension" -> mv:Ext
426
+
427
+ If Equals "pdf"
428
+ MoveFile destination="~/Documents/PDFs/"
429
+ Otherwise
430
+ If Equals "jpg"
431
+ MoveFile destination="~/Pictures/"
432
+ End If
433
+ End If
434
+ End RepeatWithEach
435
+
436
+ ShowNotification title="Done" body="Files organized!"
437
+ ```
438
+
439
+ ## Quick Note from Voice
440
+
441
+ ```scpl
442
+ DictateText -> mv:Spoken
443
+ AskLLM model="Apple Intelligence" prompt="Clean up and format: \(mv:Spoken)"
444
+ SetVariable v:CleanedNote
445
+
446
+ CreateNote title="Voice Note" body=v:CleanedNote
447
+ ShowNotification title="Saved" body="Voice note created"
448
+ ```
449
+
450
+ ---
451
+
452
+ # Tips & Common Patterns
453
+
454
+ ## Error Handling Pattern
455
+ ```scpl
456
+ GetFile path="~/file.txt" errorIfNotFound=false -> mv:File
457
+ Count
458
+ If Equals 0
459
+ ShowAlert title="Error" message="File not found"
460
+ ExitShortcut
461
+ End If
462
+ # Continue with file...
463
+ ```
464
+
465
+ ## User Input Validation
466
+ ```scpl
467
+ AskForInput prompt="Enter a number" -> mv:Input
468
+ If "is not" "Number"
469
+ ShowAlert title="Error" message="Please enter a valid number"
470
+ ExitShortcut
471
+ End If
472
+ ```
473
+
474
+ ## Chaining API Calls
475
+ ```scpl
476
+ URL "https://api.example.com/data"
477
+ GetContentsOfURL -> mv:Response
478
+ GetDictionaryValue key="items"
479
+ RepeatWithEach
480
+ # Process each item
481
+ End RepeatWithEach
482
+ ```
483
+
484
+ ---
485
+
486
+ # Quick Reference
487
+
488
+ | Task | ScPL Code |
489
+ |------|-----------|
490
+ | Show text | `ShowResult "Hello"` |
491
+ | Get clipboard | `GetClipboard` |
492
+ | Set clipboard | `SetClipboard "text"` |
493
+ | User input | `AskForInput prompt="Question"` |
494
+ | Run shell | `RunShellScript shell="/bin/zsh" script="cmd"` |
495
+ | AI prompt | `AskLLM model="Apple Intelligence" prompt="..."` |
496
+ | Variable | `Text "x" -> v:Name` then `\(v:Name)` |
497
+ | Magic var | `Text "x" -> mv:Name` then `mv:Name` |
498
+ | Condition | `If Equals "value"` ... `End If` |
499
+ | Loop | `Repeat 5` ... `End Repeat` |
500
+ | Menu | `ChooseFromMenu "title" [options]` ... `End Menu` |
501
+
502
+ ---
503
+
504
+ **493 total actions available.** Use `list_actions` tool to search by category or keyword.
package/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  } from "@modelcontextprotocol/sdk/types.js";
11
11
  import pkg from "scpl-macos-updated";
12
12
  const { convert } = pkg;
13
- import { writeFileSync, readFileSync, existsSync, mkdirSync } from "fs";
13
+ import { writeFileSync, readFileSync, existsSync, mkdirSync, appendFileSync } from "fs";
14
14
  import { join, dirname } from "path";
15
15
  import { homedir } from "os";
16
16
  import { fileURLToPath } from "url";
@@ -29,20 +29,31 @@ USAGE:
29
29
  npx scpl-updated-mcp-server [OPTIONS]
30
30
 
31
31
  OPTIONS:
32
- --setup Auto-install for Claude Code
32
+ --setup Auto-install for Claude Code (CLI)
33
+ --setup-desktop Auto-install for Claude Desktop (GUI app)
33
34
  --setup-codex Auto-install for OpenAI Codex CLI (~/.codex)
34
35
  --setup-codex=<dir> Auto-install for Codex forks with custom directory
35
36
  --help, -h Show this help message
36
37
 
38
+ You can combine multiple flags to set up multiple tools at once:
39
+ npx scpl-updated-mcp-server --setup --setup-desktop --setup-codex
40
+
37
41
  EXAMPLES:
42
+ # Claude Code (CLI) only
38
43
  npx scpl-updated-mcp-server --setup
44
+
45
+ # Claude Desktop (GUI app) only
46
+ npx scpl-updated-mcp-server --setup-desktop
47
+
48
+ # Codex only
39
49
  npx scpl-updated-mcp-server --setup-codex
40
- npx scpl-updated-mcp-server --setup-codex=~/.code
41
- npx scpl-updated-mcp-server --setup-codex=/path/to/code_config
42
50
 
43
- For Codex forks like just-every/code that use CODE_HOME or CODEX_HOME:
51
+ # Custom Codex directory (just-every/code, etc.)
44
52
  npx scpl-updated-mcp-server --setup-codex=$CODE_HOME
45
53
 
54
+ # All Claude + Codex tools at once
55
+ npx scpl-updated-mcp-server --setup --setup-desktop --setup-codex
56
+
46
57
  After setup, restart your AI coding tool and ask:
47
58
  "Create a shortcut that starts a timer and plays a sound"
48
59
  `);
@@ -50,303 +61,324 @@ After setup, restart your AI coding tool and ask:
50
61
  }
51
62
 
52
63
  // ============================================================================
53
- // CODEX SETUP: Run with --setup-codex or --setup-codex=<dir>
64
+ // SETUP FUNCTIONS
54
65
  // ============================================================================
55
- const codexArg = process.argv.find(arg => arg.startsWith("--setup-codex"));
56
- if (codexArg) {
57
- // Check for custom directory: --setup-codex=/path/to/dir or --setup-codex=~/custom
58
- let codexDir = join(homedir(), ".codex"); // default
59
66
 
60
- if (codexArg.includes("=")) {
61
- let customDir = codexArg.split("=")[1];
62
- // Expand ~ to home directory
63
- if (customDir.startsWith("~")) {
64
- customDir = customDir.replace("~", homedir());
65
- }
66
- codexDir = customDir;
67
- }
67
+ function setupClaudeCode() {
68
+ console.log("═══════════════════════════════════════════════════════════════");
69
+ console.log("šŸš€ Setting up ScPL Shortcuts for Claude Code...");
70
+ console.log("═══════════════════════════════════════════════════════════════\n");
68
71
 
69
- console.log(`šŸš€ Setting up ScPL Shortcuts for Codex at ${codexDir}...\n`);
70
-
71
- const codexConfigPath = join(codexDir, "config.toml");
72
- const skillDir = join(codexDir, "skills", "scpl-shortcuts");
72
+ const claudeJsonPath = join(homedir(), ".claude.json");
73
+ const pluginsDir = join(homedir(), ".claude", "plugins", "local", "scpl-shortcuts");
74
+ const installedPluginsPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
73
75
 
74
- // Step 1: Add MCP server to config.toml
75
- console.log(`šŸ“ Step 1: Adding MCP server to ${codexConfigPath}...`);
76
+ // Step 1: Add MCP server to ~/.claude.json
77
+ console.log("šŸ“ Step 1: Adding MCP server to ~/.claude.json...");
76
78
  try {
77
- let config = "";
78
- if (existsSync(codexConfigPath)) {
79
- config = readFileSync(codexConfigPath, "utf-8");
79
+ let claudeConfig = {};
80
+ if (existsSync(claudeJsonPath)) {
81
+ claudeConfig = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
80
82
  }
81
83
 
82
- // Check if already configured
83
- if (config.includes('[mcp_servers."scpl-shortcuts"]') || config.includes('[mcp_servers.scpl-shortcuts]')) {
84
+ if (!claudeConfig.mcpServers) {
85
+ claudeConfig.mcpServers = {};
86
+ }
87
+
88
+ if (claudeConfig.mcpServers["scpl-shortcuts"]) {
84
89
  console.log(" ā­ļø Already configured, skipping...\n");
85
90
  } else {
86
- const tomlBlock = `
87
- [mcp_servers.scpl-shortcuts]
88
- command = "npx"
89
- args = ["-y", "scpl-updated-mcp-server"]
90
- startup_timeout_sec = 60.0
91
- `;
92
- writeFileSync(codexConfigPath, config + tomlBlock);
91
+ claudeConfig.mcpServers["scpl-shortcuts"] = {
92
+ type: "stdio",
93
+ command: "npx",
94
+ args: ["-y", "scpl-updated-mcp-server"]
95
+ };
96
+ writeFileSync(claudeJsonPath, JSON.stringify(claudeConfig, null, 2));
93
97
  console.log(" āœ… MCP server added!\n");
94
98
  }
95
99
  } catch (error) {
96
- console.error(" āŒ Failed to update config:", error.message);
97
- console.log(" Add this to ~/.codex/config.toml manually:");
98
- console.log(`
99
- [mcp_servers.scpl-shortcuts]
100
- command = "npx"
101
- args = ["-y", "scpl-updated-mcp-server"]
102
- startup_timeout_sec = 60.0
103
- `);
100
+ console.error(" āŒ Failed:", error.message, "\n");
104
101
  }
105
102
 
106
- // Step 2: Install skill
107
- console.log(`šŸ“ Step 2: Installing skill to ${skillDir}...`);
103
+ // Step 2: Create plugin directory and files
104
+ console.log("šŸ“ Step 2: Installing plugin files...");
108
105
  try {
109
- mkdirSync(skillDir, { recursive: true });
106
+ mkdirSync(join(pluginsDir, "skills"), { recursive: true });
110
107
 
111
- const skillContent = `---
112
- name: scpl-shortcuts
113
- description: Create macOS Shortcuts using natural language. Use when users want to create, generate, or build Apple Shortcuts. Converts requests to ScPL code and generates .shortcut files.
114
- metadata:
115
- short-description: Create macOS Shortcuts with AI
108
+ const pluginJson = {
109
+ name: "scpl-shortcuts",
110
+ version: "1.0.0",
111
+ description: "Create macOS Shortcuts using natural language and ScPL",
112
+ skills: [
113
+ {
114
+ name: "create-shortcut",
115
+ description: "Create a macOS Shortcut using natural language.",
116
+ path: "skills/create-shortcut.md"
117
+ }
118
+ ]
119
+ };
120
+ writeFileSync(join(pluginsDir, "plugin.json"), JSON.stringify(pluginJson, null, 2));
121
+
122
+ // Read comprehensive ScPL reference
123
+ const refPath = join(__dirname, "SCPL_REFERENCE.md");
124
+ let skillContent = "";
125
+ if (existsSync(refPath)) {
126
+ const reference = readFileSync(refPath, "utf-8");
127
+ skillContent = `---
128
+ description: Create macOS Shortcuts using natural language with ScPL.
129
+ tags: [shortcuts, automation, macos, scpl, apple-intelligence]
116
130
  ---
117
131
 
118
132
  # ScPL Shortcuts Skill
119
133
 
120
- Create macOS Shortcuts using natural language with 493 available actions.
121
-
122
- ## MCP Tools Available
123
-
124
- You have access to the \`scpl-shortcuts\` MCP server with these tools:
125
-
126
- | Tool | Description |
127
- |------|-------------|
128
- | \`create_shortcut\` | Generate a .shortcut file from ScPL code |
129
- | \`validate_scpl\` | Check if ScPL code is valid before creating |
130
- | \`list_actions\` | Search available actions by category or keyword |
134
+ You have access to the ScPL MCP server with **493 actions**.
131
135
 
132
- ## ScPL Syntax
136
+ ## Available Tools
137
+ - \`create_shortcut\` - Convert ScPL code to .shortcut file
138
+ - \`validate_scpl\` - Check syntax without creating file
139
+ - \`list_actions\` - Search available actions by category/keyword
133
140
 
134
- ScPL is line-based. Each line is an action. Parameters use \`key=value\` or \`key="value"\`.
141
+ ${reference}
142
+ `;
143
+ } else {
144
+ // Fallback minimal skill if reference not found
145
+ skillContent = `---
146
+ description: Create macOS Shortcuts using natural language.
147
+ tags: [shortcuts, automation, macos, scpl]
148
+ ---
135
149
 
136
- \`\`\`scpl
137
- # Comments start with #
138
- Text "Hello World"
139
- ShowResult
150
+ # Create Shortcut Skill
140
151
 
141
- # Variables
142
- Text "some value"
143
- SetVariable v:myVar
144
- ShowResult v:myVar
152
+ You have access to the ScPL MCP server with 493 actions.
153
+ Tools: create_shortcut, validate_scpl, list_actions
145
154
 
146
- # AI actions
147
- AskLLM model="Apple Intelligence" prompt="Summarize this"
148
- AskChatGPT prompt="Explain this"
149
- \`\`\`
155
+ Basic syntax: \`ActionName "arg"\` or \`ActionName param=value\`
156
+ Variables: \`v:Named\`, \`mv:Magic\`, \`s:Special\`
157
+ Flow: \`If\`/\`End If\`, \`Repeat\`/\`End Repeat\`
158
+ `;
159
+ }
160
+ writeFileSync(join(pluginsDir, "skills", "create-shortcut.md"), skillContent);
161
+ console.log(" āœ… Plugin files created!\n");
162
+ } catch (error) {
163
+ console.error(" āŒ Failed:", error.message, "\n");
164
+ }
150
165
 
151
- ## Popular Actions by Category
166
+ // Step 3: Register plugin
167
+ console.log("šŸ“‹ Step 3: Registering plugin...");
168
+ try {
169
+ let installedPlugins = { version: 2, plugins: {} };
170
+ if (existsSync(installedPluginsPath)) {
171
+ installedPlugins = JSON.parse(readFileSync(installedPluginsPath, "utf-8"));
172
+ }
152
173
 
153
- **AI**: AskLLM, AskChatGPT, AskClaude
154
- **Clock**: StartStopwatch, StopStopwatch, CreateAlarm
155
- **Voice Memos**: CreateRecording, PlayRecording
156
- **System**: SetDarkMode, TakeScreenshot, LockScreen
157
- **Files**: GetFile, SaveFile, RenameFile, RevealInFinder
158
- **Scripting**: RunShellScript, RunAppleScript, RunJavaScriptForAutomation
159
- **Clipboard**: GetClipboard, SetClipboard
174
+ if (installedPlugins.plugins["scpl-shortcuts@local"]) {
175
+ console.log(" ā­ļø Already registered, skipping...\n");
176
+ } else {
177
+ installedPlugins.plugins["scpl-shortcuts@local"] = [
178
+ {
179
+ scope: "user",
180
+ installPath: pluginsDir,
181
+ version: "1.0.0",
182
+ installedAt: new Date().toISOString(),
183
+ lastUpdated: new Date().toISOString(),
184
+ isLocal: true
185
+ }
186
+ ];
187
+ writeFileSync(installedPluginsPath, JSON.stringify(installedPlugins, null, 2));
188
+ console.log(" āœ… Plugin registered!\n");
189
+ }
190
+ } catch (error) {
191
+ console.error(" āŒ Failed:", error.message, "\n");
192
+ }
160
193
 
161
- ## Workflow
194
+ console.log("āœ… Claude Code setup complete!\n");
195
+ }
162
196
 
163
- 1. User describes what shortcut they want
164
- 2. Use \`list_actions\` if you need to find specific actions
165
- 3. Write ScPL code for the shortcut
166
- 4. Use \`validate_scpl\` to check syntax
167
- 5. Use \`create_shortcut\` to generate the .shortcut file
168
- 6. Tell user to install via Shortcut Source Helper from RoutineHub
197
+ function setupClaudeDesktop() {
198
+ console.log("═══════════════════════════════════════════════════════════════");
199
+ console.log("šŸš€ Setting up ScPL Shortcuts for Claude Desktop...");
200
+ console.log("═══════════════════════════════════════════════════════════════\n");
201
+
202
+ // Determine config path based on OS
203
+ let configPath;
204
+ const platform = process.platform;
205
+ if (platform === "darwin") {
206
+ configPath = join(homedir(), "Library", "Application Support", "Claude", "claude_desktop_config.json");
207
+ } else if (platform === "win32") {
208
+ configPath = join(process.env.APPDATA || "", "Claude", "claude_desktop_config.json");
209
+ } else {
210
+ configPath = join(homedir(), ".config", "Claude", "claude_desktop_config.json");
211
+ }
169
212
 
170
- ## Example: Timer with Notification
213
+ console.log(`šŸ“ Adding MCP server to ${configPath}...`);
214
+ try {
215
+ // Ensure directory exists
216
+ mkdirSync(dirname(configPath), { recursive: true });
171
217
 
172
- \`\`\`scpl
173
- # Start a 25-minute Pomodoro timer
174
- StartTimer minutes=25
175
- ShowAlert title="Timer Started" message="Focus for 25 minutes!"
176
- \`\`\`
218
+ let config = {};
219
+ if (existsSync(configPath)) {
220
+ config = JSON.parse(readFileSync(configPath, "utf-8"));
221
+ }
177
222
 
178
- ## Example: Clipboard AI Enhancement
223
+ if (!config.mcpServers) {
224
+ config.mcpServers = {};
225
+ }
179
226
 
180
- \`\`\`scpl
181
- GetClipboard
182
- SetVariable v:text
183
- AskChatGPT prompt="Improve this text: \\(v:text)"
184
- SetClipboard
185
- ShowAlert title="Done" message="Improved text copied!"
186
- \`\`\`
187
- `;
188
- writeFileSync(join(skillDir, "SKILL.md"), skillContent);
189
- console.log(" āœ… Skill installed!\n");
227
+ if (config.mcpServers["scpl-shortcuts"]) {
228
+ console.log(" ā­ļø Already configured, skipping...\n");
229
+ } else {
230
+ config.mcpServers["scpl-shortcuts"] = {
231
+ command: "npx",
232
+ args: ["-y", "scpl-updated-mcp-server"]
233
+ };
234
+ writeFileSync(configPath, JSON.stringify(config, null, 2));
235
+ console.log(" āœ… MCP server added!\n");
236
+ }
190
237
  } catch (error) {
191
- console.error(" āŒ Failed to install skill:", error.message, "\n");
238
+ console.error(" āŒ Failed:", error.message, "\n");
192
239
  }
193
240
 
194
- console.log("šŸŽ‰ Setup complete! Restart Codex to use the shortcuts tools.\n");
195
- console.log("Usage: Just ask Codex to create a shortcut!");
196
- console.log(' Example: "Create a shortcut that starts a timer and plays a sound"\n');
197
- process.exit(0);
241
+ console.log("āœ… Claude Desktop setup complete!\n");
242
+ console.log("ā„¹ļø Note: Claude Desktop doesn't have plugins/skills.\n");
243
+ console.log(" The MCP tools (create_shortcut, validate_scpl, list_actions)");
244
+ console.log(" will be available, but Claude won't have the full ScPL reference");
245
+ console.log(" loaded as context. Consider using Claude Code for best results.\n");
198
246
  }
199
247
 
200
- // ============================================================================
201
- // CLAUDE CODE SETUP: Run with --setup to install everything automatically
202
- // ============================================================================
203
- if (process.argv.includes("--setup")) {
204
- console.log("šŸš€ Setting up ScPL Shortcuts for Claude Code...\n");
248
+ function setupCodex(codexDir) {
249
+ console.log("═══════════════════════════════════════════════════════════════");
250
+ console.log(`šŸš€ Setting up ScPL Shortcuts for Codex at ${codexDir}...`);
251
+ console.log("═══════════════════════════════════════════════════════════════\n");
205
252
 
206
- const claudeJsonPath = join(homedir(), ".claude.json");
207
- const pluginsDir = join(homedir(), ".claude", "plugins", "local", "scpl-shortcuts");
208
- const installedPluginsPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
253
+ const codexConfigPath = join(codexDir, "config.toml");
254
+ const skillDir = join(codexDir, "skills", "scpl-shortcuts");
209
255
 
210
- // Step 1: Add MCP server to ~/.claude.json
211
- console.log("šŸ“ Step 1: Adding MCP server to ~/.claude.json...");
256
+ // Step 1: Add MCP server to config.toml
257
+ console.log(`šŸ“ Step 1: Adding MCP server to ${codexConfigPath}...`);
212
258
  try {
213
- let claudeConfig = {};
214
- if (existsSync(claudeJsonPath)) {
215
- claudeConfig = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
259
+ let config = "";
260
+ if (existsSync(codexConfigPath)) {
261
+ config = readFileSync(codexConfigPath, "utf-8");
216
262
  }
217
263
 
218
- if (!claudeConfig.mcpServers) {
219
- claudeConfig.mcpServers = {};
264
+ if (config.includes('[mcp_servers."scpl-shortcuts"]') || config.includes('[mcp_servers.scpl-shortcuts]')) {
265
+ console.log(" ā­ļø Already configured, skipping...\n");
266
+ } else {
267
+ const tomlBlock = `
268
+ [mcp_servers.scpl-shortcuts]
269
+ command = "npx"
270
+ args = ["-y", "scpl-updated-mcp-server"]
271
+ startup_timeout_sec = 60.0
272
+ `;
273
+ writeFileSync(codexConfigPath, config + tomlBlock);
274
+ console.log(" āœ… MCP server added!\n");
220
275
  }
221
-
222
- claudeConfig.mcpServers["scpl-shortcuts"] = {
223
- type: "stdio",
224
- command: "npx",
225
- args: ["-y", "scpl-updated-mcp-server"]
226
- };
227
-
228
- writeFileSync(claudeJsonPath, JSON.stringify(claudeConfig, null, 2));
229
- console.log(" āœ… MCP server added!\n");
230
276
  } catch (error) {
231
- console.error(" āŒ Failed to update ~/.claude.json:", error.message);
232
- console.log(" You can manually add this to ~/.claude.json under mcpServers:");
233
- console.log(` "scpl-shortcuts": { "type": "stdio", "command": "npx", "args": ["-y", "scpl-updated-mcp-server"] }\n`);
277
+ console.error(" āŒ Failed:", error.message, "\n");
234
278
  }
235
279
 
236
- // Step 2: Create plugin directory and files
237
- console.log("šŸ“ Step 2: Installing plugin files...");
280
+ // Step 2: Install skill
281
+ console.log(`šŸ“ Step 2: Installing skill to ${skillDir}...`);
238
282
  try {
239
- mkdirSync(join(pluginsDir, "skills"), { recursive: true });
240
-
241
- // Write plugin.json
242
- const pluginJson = {
243
- name: "scpl-shortcuts",
244
- version: "1.0.0",
245
- description: "Create macOS Shortcuts using natural language and ScPL",
246
- skills: [
247
- {
248
- name: "create-shortcut",
249
- description: "Create a macOS Shortcut using natural language. Guides you through the process and generates a .shortcut file.",
250
- path: "skills/create-shortcut.md"
251
- }
252
- ]
253
- };
254
- writeFileSync(join(pluginsDir, "plugin.json"), JSON.stringify(pluginJson, null, 2));
283
+ mkdirSync(skillDir, { recursive: true });
255
284
 
256
- // Write skill file
257
- const skillContent = `---
258
- description: Create macOS Shortcuts using natural language. Converts your request into ScPL code and generates a .shortcut file.
259
- tags: [shortcuts, automation, macos, scpl]
285
+ // Read comprehensive ScPL reference
286
+ const refPath = join(__dirname, "SCPL_REFERENCE.md");
287
+ let skillContent = "";
288
+ if (existsSync(refPath)) {
289
+ const reference = readFileSync(refPath, "utf-8");
290
+ skillContent = `---
291
+ name: scpl-shortcuts
292
+ description: Create macOS Shortcuts using natural language with ScPL.
293
+ metadata:
294
+ short-description: Create macOS Shortcuts with AI
260
295
  ---
261
296
 
262
- # Create Shortcut Skill
297
+ # ScPL Shortcuts Skill
263
298
 
264
- You have access to the ScPL MCP server with 493 actions for creating macOS Shortcuts.
299
+ You have access to the ScPL MCP server with **493 actions**.
265
300
 
266
301
  ## Available Tools
302
+ - \`create_shortcut\` - Convert ScPL code to .shortcut file
303
+ - \`validate_scpl\` - Check syntax without creating file
304
+ - \`list_actions\` - Search available actions by category/keyword
267
305
 
268
- 1. **create_shortcut** - Generate a .shortcut file from ScPL code
269
- 2. **validate_scpl** - Check if ScPL code is valid before creating
270
- 3. **list_actions** - Search available actions by category or keyword
306
+ ${reference}
307
+ `;
308
+ } else {
309
+ // Fallback minimal skill
310
+ skillContent = `---
311
+ name: scpl-shortcuts
312
+ description: Create macOS Shortcuts using natural language.
313
+ metadata:
314
+ short-description: Create macOS Shortcuts with AI
315
+ ---
271
316
 
272
- ## Popular Action Categories
317
+ # ScPL Shortcuts Skill
273
318
 
274
- - **AI**: AskLLM (Apple Intelligence), AskChatGPT, AskClaude
275
- - **Clock**: StartStopwatch, CreateAlarm, GetCurrentTime
276
- - **Voice Memos**: CreateRecording, PlayRecording
277
- - **System**: SetDarkMode, TakeScreenshot, LockScreen
278
- - **Files**: GetFile, SaveFile, RenameFile, RevealInFinder
279
- - **Scripting**: RunShellScript, RunAppleScript
319
+ 493 actions available. Tools: create_shortcut, validate_scpl, list_actions
280
320
 
281
- ## ScPL Syntax Examples
321
+ Basic syntax: \`ActionName "arg"\` or \`ActionName param=value\`
322
+ Variables: \`v:Named\`, \`mv:Magic\`, \`s:Special\`
323
+ Flow: \`If\`/\`End If\`, \`Repeat\`/\`End Repeat\`
324
+ `;
325
+ }
326
+ writeFileSync(join(skillDir, "SKILL.md"), skillContent);
327
+ console.log(" āœ… Skill installed!\n");
328
+ } catch (error) {
329
+ console.error(" āŒ Failed:", error.message, "\n");
330
+ }
282
331
 
283
- \`\`\`scpl
284
- # Simple notification
285
- ShowResult "Hello World!"
332
+ console.log(`āœ… Codex setup complete for ${codexDir}!\n`);
333
+ }
286
334
 
287
- # Use Apple Intelligence
288
- Text "Summarize this for me"
289
- AskLLM model="Apple Intelligence" prompt="Make it shorter"
290
- ShowResult
335
+ // ============================================================================
336
+ // PROCESS SETUP FLAGS
337
+ // ============================================================================
291
338
 
292
- # Shell script
293
- RunShellScript shell="/bin/zsh" script="echo Hello"
294
- ShowResult
339
+ let didSetup = false;
295
340
 
296
- # Variables
297
- Text "Hello"
298
- SetVariable v:greeting
299
- ShowResult v:greeting
300
- \`\`\`
341
+ // Claude Code setup
342
+ if (process.argv.includes("--setup")) {
343
+ setupClaudeCode();
344
+ didSetup = true;
345
+ }
301
346
 
302
- ## Workflow
347
+ // Claude Desktop setup
348
+ if (process.argv.includes("--setup-desktop")) {
349
+ setupClaudeDesktop();
350
+ didSetup = true;
351
+ }
303
352
 
304
- 1. User describes what they want
305
- 2. Use \`list_actions\` if you need to find specific actions
306
- 3. Write ScPL code for the shortcut
307
- 4. Use \`validate_scpl\` to check syntax
308
- 5. Use \`create_shortcut\` to generate the .shortcut file
309
- 6. Tell user to drag the file onto Shortcut Source Helper to install
310
- `;
311
- writeFileSync(join(pluginsDir, "skills", "create-shortcut.md"), skillContent);
312
- console.log(" āœ… Plugin files created!\n");
313
- } catch (error) {
314
- console.error(" āŒ Failed to create plugin files:", error.message, "\n");
315
- }
353
+ // Codex setups (can have multiple --setup-codex and --setup-codex=<dir>)
354
+ const codexArgs = process.argv.filter(arg => arg.startsWith("--setup-codex"));
355
+ for (const codexArg of codexArgs) {
356
+ let codexDir = join(homedir(), ".codex"); // default
316
357
 
317
- // Step 3: Register plugin in installed_plugins.json
318
- console.log("šŸ“‹ Step 3: Registering plugin...");
319
- try {
320
- let installedPlugins = { version: 2, plugins: {} };
321
- if (existsSync(installedPluginsPath)) {
322
- installedPlugins = JSON.parse(readFileSync(installedPluginsPath, "utf-8"));
358
+ if (codexArg.includes("=")) {
359
+ let customDir = codexArg.split("=")[1];
360
+ if (customDir.startsWith("~")) {
361
+ customDir = customDir.replace("~", homedir());
323
362
  }
324
-
325
- installedPlugins.plugins["scpl-shortcuts@local"] = [
326
- {
327
- scope: "user",
328
- installPath: pluginsDir,
329
- version: "1.0.0",
330
- installedAt: new Date().toISOString(),
331
- lastUpdated: new Date().toISOString(),
332
- isLocal: true
333
- }
334
- ];
335
-
336
- writeFileSync(installedPluginsPath, JSON.stringify(installedPlugins, null, 2));
337
- console.log(" āœ… Plugin registered!\n");
338
- } catch (error) {
339
- console.error(" āŒ Failed to register plugin:", error.message, "\n");
363
+ codexDir = customDir;
340
364
  }
341
365
 
342
- console.log("šŸŽ‰ Setup complete! Restart Claude Code to use the shortcuts tools.\n");
343
- console.log("Usage: Just ask Claude to create a shortcut!");
344
- console.log(' Example: "Create a shortcut that starts a timer and plays a sound"\n');
366
+ setupCodex(codexDir);
367
+ didSetup = true;
368
+ }
369
+
370
+ // Exit after setup(s)
371
+ if (didSetup) {
372
+ console.log("═══════════════════════════════════════════════════════════════");
373
+ console.log("šŸŽ‰ All setups complete! Restart your AI tool(s) to use shortcuts.");
374
+ console.log("═══════════════════════════════════════════════════════════════");
375
+ console.log('\nUsage: Just ask to create a shortcut!');
376
+ console.log(' Example: "Create a shortcut that starts a timer"\n');
345
377
  process.exit(0);
346
378
  }
347
379
 
348
380
  // ============================================================================
349
- // MCP SERVER
381
+ // MCP SERVER (runs if no setup flags)
350
382
  // ============================================================================
351
383
 
352
384
  const server = new Server(
@@ -430,24 +462,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
430
462
  if (name === "create_shortcut") {
431
463
  const { scpl_code, output_name, output_dir } = args;
432
464
 
433
- // Convert ScPL to shortcut
434
465
  const shortcutBuffer = convert(scpl_code, {
435
466
  makePlist: true,
436
467
  makeShortcut: true,
437
468
  });
438
469
 
439
- // Determine output path (default to ~/Documents)
440
470
  const dir = output_dir || join(homedir(), "Documents");
441
471
  const outputPath = join(dir, `${output_name}.shortcut`);
442
472
 
443
- // Write the file
444
473
  writeFileSync(outputPath, shortcutBuffer);
445
474
 
446
475
  return {
447
476
  content: [
448
477
  {
449
478
  type: "text",
450
- text: `āœ… Shortcut created successfully!\n\nPath: ${outputPath}\n\nšŸ“ To install:\n1. Download "Shortcut Source Helper" from RoutineHub\n2. Drag ${output_name}.shortcut onto it\n3. Follow the prompts to sign and import\n\nThe shortcut will be added to your Shortcuts app!`,
479
+ text: `āœ… Shortcut created!\n\nPath: ${outputPath}\n\nTo install: Drag onto Shortcut Source Helper from RoutineHub`,
451
480
  },
452
481
  ],
453
482
  };
@@ -457,69 +486,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
457
486
  const { scpl_code } = args;
458
487
 
459
488
  try {
460
- convert(scpl_code, {
461
- makePlist: false,
462
- makeShortcut: false,
463
- });
464
-
465
- return {
466
- content: [
467
- {
468
- type: "text",
469
- text: "āœ… ScPL code is valid!",
470
- },
471
- ],
472
- };
489
+ convert(scpl_code, { makePlist: false, makeShortcut: false });
490
+ return { content: [{ type: "text", text: "āœ… ScPL code is valid!" }] };
473
491
  } catch (error) {
474
- return {
475
- content: [
476
- {
477
- type: "text",
478
- text: `āŒ ScPL validation failed:\n\n${error.message}`,
479
- },
480
- ],
481
- isError: true,
482
- };
492
+ return { content: [{ type: "text", text: `āŒ Invalid: ${error.message}` }], isError: true };
483
493
  }
484
494
  }
485
495
 
486
496
  if (name === "list_actions") {
487
497
  const { category, search } = args || {};
488
498
 
489
- // Embedded action list (top actions for quick reference)
490
499
  const topActions = {
491
- // AI
492
500
  "is.workflow.actions.askllm": { Name: "Ask LLM", Category: "AI" },
493
501
  "is.workflow.actions.askchatgpt": { Name: "Ask ChatGPT", Category: "AI" },
494
502
  "com.anthropic.claudeforipad.AskClaudeIntentExtension": { Name: "Ask Claude", Category: "AI" },
495
- // Clock
496
503
  "com.apple.clock.StartStopwatchIntent": { Name: "Start Stopwatch", Category: "Clock" },
497
504
  "com.apple.clock.StopStopwatchIntent": { Name: "Stop Stopwatch", Category: "Clock" },
498
505
  "com.apple.clock.CreateAlarmIntent": { Name: "Create Alarm", Category: "Clock" },
499
- // Voice Memos
500
506
  "com.apple.VoiceMemos.CreateRecordingIntent": { Name: "Create Recording", Category: "Voice Memos" },
501
507
  "com.apple.VoiceMemos.PlayRecordingIntent": { Name: "Play Recording", Category: "Voice Memos" },
502
- // System
503
508
  "is.workflow.actions.appearance": { Name: "Set Dark/Light Mode", Category: "System" },
504
509
  "is.workflow.actions.takescreenshot": { Name: "Take Screenshot", Category: "System" },
505
510
  "is.workflow.actions.lockscreen": { Name: "Lock Screen", Category: "System" },
506
- // Scripting
507
511
  "is.workflow.actions.runshellscript": { Name: "Run Shell Script", Category: "Scripting" },
508
512
  "is.workflow.actions.runapplescript": { Name: "Run AppleScript", Category: "Scripting" },
509
513
  "is.workflow.actions.runjavascriptforautomation": { Name: "Run JavaScript", Category: "Scripting" },
510
- // Files
511
514
  "is.workflow.actions.file.getfile": { Name: "Get File", Category: "Files" },
512
515
  "is.workflow.actions.file.savefile": { Name: "Save File", Category: "Files" },
513
- "is.workflow.actions.file.renamefile": { Name: "Rename File", Category: "Files" },
514
- "is.workflow.actions.file.revealfile": { Name: "Reveal in Finder", Category: "Files" },
515
- // Text
516
- "is.workflow.actions.gettext": { Name: "Get Text", Category: "Text" },
517
516
  "is.workflow.actions.showresult": { Name: "Show Result", Category: "Text" },
518
517
  "is.workflow.actions.alert": { Name: "Show Alert", Category: "Text" },
519
- // Variables
520
518
  "is.workflow.actions.setvariable": { Name: "Set Variable", Category: "Variables" },
521
- "is.workflow.actions.getvariable": { Name: "Get Variable", Category: "Variables" },
522
- // Clipboard
523
519
  "is.workflow.actions.getclipboard": { Name: "Get Clipboard", Category: "Clipboard" },
524
520
  "is.workflow.actions.setclipboard": { Name: "Set Clipboard", Category: "Clipboard" },
525
521
  };
@@ -527,108 +523,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
527
523
  let filtered = Object.entries(topActions);
528
524
 
529
525
  if (category) {
530
- filtered = filtered.filter(
531
- ([_, action]) => action.Category?.toLowerCase() === category.toLowerCase()
532
- );
526
+ filtered = filtered.filter(([_, a]) => a.Category?.toLowerCase() === category.toLowerCase());
533
527
  }
534
-
535
528
  if (search) {
536
- const searchLower = search.toLowerCase();
537
- filtered = filtered.filter(
538
- ([id, action]) =>
539
- id.toLowerCase().includes(searchLower) ||
540
- action.Name?.toLowerCase().includes(searchLower) ||
541
- action.Category?.toLowerCase().includes(searchLower)
529
+ const s = search.toLowerCase();
530
+ filtered = filtered.filter(([id, a]) =>
531
+ id.toLowerCase().includes(s) || a.Name?.toLowerCase().includes(s)
542
532
  );
543
533
  }
544
534
 
545
- const results = filtered
546
- .map(([id, action]) => `• **${action.Name}** - \`${id}\` (${action.Category})`)
547
- .join("\n");
548
-
549
- return {
550
- content: [
551
- {
552
- type: "text",
553
- text: `Found ${filtered.length} actions:\n\n${results}\n\nšŸ’” This is a subset of 493 total actions. For the full list, see: https://github.com/cavingraves/scpl-macos-updated`,
554
- },
555
- ],
556
- };
535
+ const results = filtered.map(([id, a]) => `• **${a.Name}** - \`${id}\``).join("\n");
536
+ return { content: [{ type: "text", text: `${filtered.length} actions:\n\n${results}\n\n(493 total available)` }] };
557
537
  }
558
538
 
559
539
  throw new Error(`Unknown tool: ${name}`);
560
540
  } catch (error) {
561
- return {
562
- content: [
563
- {
564
- type: "text",
565
- text: `Error: ${error.message}`,
566
- },
567
- ],
568
- isError: true,
569
- };
541
+ return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
570
542
  }
571
543
  });
572
544
 
573
- // Resource handlers
574
545
  server.setRequestHandler(ListResourcesRequestSchema, async () => {
575
- return {
576
- resources: [
577
- {
578
- uri: "scpl://examples",
579
- name: "ScPL Examples",
580
- description: "Example shortcuts written in ScPL",
581
- mimeType: "text/markdown",
582
- },
583
- ],
584
- };
546
+ return { resources: [{ uri: "scpl://examples", name: "ScPL Examples", mimeType: "text/markdown" }] };
585
547
  });
586
548
 
587
549
  server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
588
- const { uri } = request.params;
589
-
590
- if (uri === "scpl://examples") {
591
- const examples = `# ScPL Examples
592
-
593
- ## Apple Intelligence
594
- \`\`\`scpl
595
- Text "Summarize this document"
596
- AskLLM model="Apple Intelligence" prompt="Make it concise"
597
- ShowResult
598
- \`\`\`
599
-
600
- ## Timer with Sound
601
- \`\`\`scpl
602
- # Start a 5-minute timer
603
- StartTimer minutes=5
604
- ShowAlert title="Timer Started" message="5 minutes"
605
- \`\`\`
606
-
607
- ## Shell Script
608
- \`\`\`scpl
609
- RunShellScript shell="/bin/zsh" script="echo Hello World"
610
- ShowResult
611
- \`\`\`
612
-
613
- ## Clipboard Workflow
614
- \`\`\`scpl
615
- GetClipboard
616
- SetVariable v:text
617
- AskChatGPT prompt="Improve this: \\(v:text)"
618
- SetClipboard
619
- ShowAlert title="Done" message="Improved text copied!"
620
- \`\`\`
621
- `;
622
-
623
- return {
624
- contents: [{ uri, mimeType: "text/markdown", text: examples }],
625
- };
550
+ if (request.params.uri === "scpl://examples") {
551
+ return { contents: [{ uri: "scpl://examples", mimeType: "text/markdown", text: "# Examples\n\n```scpl\nShowResult \"Hello!\"\n```" }] };
626
552
  }
627
-
628
- throw new Error(`Unknown resource: ${uri}`);
553
+ throw new Error("Unknown resource");
629
554
  });
630
555
 
631
- // Start server
632
556
  async function main() {
633
557
  const transport = new StdioServerTransport();
634
558
  await server.connect(transport);
package/package.json CHANGED
@@ -1,12 +1,17 @@
1
1
  {
2
2
  "name": "scpl-updated-mcp-server",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "AI-powered Apple Shortcuts creation with Claude Code! Generate macOS shortcuts using natural language. 493 actions available. MCP server for text-based shortcut programming. Vibe code your automation workflows.",
5
5
  "type": "module",
6
6
  "main": "index.js",
7
7
  "bin": {
8
8
  "scpl-updated-mcp-server": "index.js"
9
9
  },
10
+ "files": [
11
+ "index.js",
12
+ "SCPL_REFERENCE.md",
13
+ "README.md"
14
+ ],
10
15
  "scripts": {
11
16
  "start": "node index.js"
12
17
  },