scpl-updated-mcp-server 1.0.4 → 1.0.5
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.
- package/index.js +181 -350
- package/package.json +1 -1
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";
|
|
@@ -34,15 +34,22 @@ OPTIONS:
|
|
|
34
34
|
--setup-codex=<dir> Auto-install for Codex forks with custom directory
|
|
35
35
|
--help, -h Show this help message
|
|
36
36
|
|
|
37
|
+
You can combine multiple flags to set up multiple tools at once:
|
|
38
|
+
npx scpl-updated-mcp-server --setup --setup-codex --setup-codex=~/.code
|
|
39
|
+
|
|
37
40
|
EXAMPLES:
|
|
41
|
+
# Claude Code only
|
|
38
42
|
npx scpl-updated-mcp-server --setup
|
|
43
|
+
|
|
44
|
+
# Codex only
|
|
39
45
|
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
46
|
|
|
43
|
-
|
|
47
|
+
# Custom Codex directory (just-every/code, etc.)
|
|
44
48
|
npx scpl-updated-mcp-server --setup-codex=$CODE_HOME
|
|
45
49
|
|
|
50
|
+
# All at once: Claude + Codex + custom fork
|
|
51
|
+
npx scpl-updated-mcp-server --setup --setup-codex --setup-codex=~/.code
|
|
52
|
+
|
|
46
53
|
After setup, restart your AI coding tool and ask:
|
|
47
54
|
"Create a shortcut that starts a timer and plays a sound"
|
|
48
55
|
`);
|
|
@@ -50,23 +57,126 @@ After setup, restart your AI coding tool and ask:
|
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
// ============================================================================
|
|
53
|
-
//
|
|
60
|
+
// SETUP FUNCTIONS
|
|
54
61
|
// ============================================================================
|
|
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
62
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
function setupClaudeCode() {
|
|
64
|
+
console.log("═══════════════════════════════════════════════════════════════");
|
|
65
|
+
console.log("🚀 Setting up ScPL Shortcuts for Claude Code...");
|
|
66
|
+
console.log("═══════════════════════════════════════════════════════════════\n");
|
|
67
|
+
|
|
68
|
+
const claudeJsonPath = join(homedir(), ".claude.json");
|
|
69
|
+
const pluginsDir = join(homedir(), ".claude", "plugins", "local", "scpl-shortcuts");
|
|
70
|
+
const installedPluginsPath = join(homedir(), ".claude", "plugins", "installed_plugins.json");
|
|
71
|
+
|
|
72
|
+
// Step 1: Add MCP server to ~/.claude.json
|
|
73
|
+
console.log("📝 Step 1: Adding MCP server to ~/.claude.json...");
|
|
74
|
+
try {
|
|
75
|
+
let claudeConfig = {};
|
|
76
|
+
if (existsSync(claudeJsonPath)) {
|
|
77
|
+
claudeConfig = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
|
|
65
78
|
}
|
|
66
|
-
|
|
79
|
+
|
|
80
|
+
if (!claudeConfig.mcpServers) {
|
|
81
|
+
claudeConfig.mcpServers = {};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (claudeConfig.mcpServers["scpl-shortcuts"]) {
|
|
85
|
+
console.log(" ⏭️ Already configured, skipping...\n");
|
|
86
|
+
} else {
|
|
87
|
+
claudeConfig.mcpServers["scpl-shortcuts"] = {
|
|
88
|
+
type: "stdio",
|
|
89
|
+
command: "npx",
|
|
90
|
+
args: ["-y", "scpl-updated-mcp-server"]
|
|
91
|
+
};
|
|
92
|
+
writeFileSync(claudeJsonPath, JSON.stringify(claudeConfig, null, 2));
|
|
93
|
+
console.log(" ✅ MCP server added!\n");
|
|
94
|
+
}
|
|
95
|
+
} catch (error) {
|
|
96
|
+
console.error(" ❌ Failed:", error.message, "\n");
|
|
67
97
|
}
|
|
68
98
|
|
|
69
|
-
|
|
99
|
+
// Step 2: Create plugin directory and files
|
|
100
|
+
console.log("📁 Step 2: Installing plugin files...");
|
|
101
|
+
try {
|
|
102
|
+
mkdirSync(join(pluginsDir, "skills"), { recursive: true });
|
|
103
|
+
|
|
104
|
+
const pluginJson = {
|
|
105
|
+
name: "scpl-shortcuts",
|
|
106
|
+
version: "1.0.0",
|
|
107
|
+
description: "Create macOS Shortcuts using natural language and ScPL",
|
|
108
|
+
skills: [
|
|
109
|
+
{
|
|
110
|
+
name: "create-shortcut",
|
|
111
|
+
description: "Create a macOS Shortcut using natural language.",
|
|
112
|
+
path: "skills/create-shortcut.md"
|
|
113
|
+
}
|
|
114
|
+
]
|
|
115
|
+
};
|
|
116
|
+
writeFileSync(join(pluginsDir, "plugin.json"), JSON.stringify(pluginJson, null, 2));
|
|
117
|
+
|
|
118
|
+
const skillContent = `---
|
|
119
|
+
description: Create macOS Shortcuts using natural language.
|
|
120
|
+
tags: [shortcuts, automation, macos, scpl]
|
|
121
|
+
---
|
|
122
|
+
|
|
123
|
+
# Create Shortcut Skill
|
|
124
|
+
|
|
125
|
+
You have access to the ScPL MCP server with 493 actions.
|
|
126
|
+
|
|
127
|
+
## Tools: create_shortcut, validate_scpl, list_actions
|
|
128
|
+
|
|
129
|
+
## ScPL Syntax
|
|
130
|
+
\`\`\`scpl
|
|
131
|
+
Text "Hello"
|
|
132
|
+
AskLLM model="Apple Intelligence" prompt="Make it fun"
|
|
133
|
+
ShowResult
|
|
134
|
+
\`\`\`
|
|
135
|
+
|
|
136
|
+
## Categories
|
|
137
|
+
AI, Clock, Voice Memos, System, Files, Scripting, Clipboard
|
|
138
|
+
`;
|
|
139
|
+
writeFileSync(join(pluginsDir, "skills", "create-shortcut.md"), skillContent);
|
|
140
|
+
console.log(" ✅ Plugin files created!\n");
|
|
141
|
+
} catch (error) {
|
|
142
|
+
console.error(" ❌ Failed:", error.message, "\n");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Step 3: Register plugin
|
|
146
|
+
console.log("📋 Step 3: Registering plugin...");
|
|
147
|
+
try {
|
|
148
|
+
let installedPlugins = { version: 2, plugins: {} };
|
|
149
|
+
if (existsSync(installedPluginsPath)) {
|
|
150
|
+
installedPlugins = JSON.parse(readFileSync(installedPluginsPath, "utf-8"));
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (installedPlugins.plugins["scpl-shortcuts@local"]) {
|
|
154
|
+
console.log(" ⏭️ Already registered, skipping...\n");
|
|
155
|
+
} else {
|
|
156
|
+
installedPlugins.plugins["scpl-shortcuts@local"] = [
|
|
157
|
+
{
|
|
158
|
+
scope: "user",
|
|
159
|
+
installPath: pluginsDir,
|
|
160
|
+
version: "1.0.0",
|
|
161
|
+
installedAt: new Date().toISOString(),
|
|
162
|
+
lastUpdated: new Date().toISOString(),
|
|
163
|
+
isLocal: true
|
|
164
|
+
}
|
|
165
|
+
];
|
|
166
|
+
writeFileSync(installedPluginsPath, JSON.stringify(installedPlugins, null, 2));
|
|
167
|
+
console.log(" ✅ Plugin registered!\n");
|
|
168
|
+
}
|
|
169
|
+
} catch (error) {
|
|
170
|
+
console.error(" ❌ Failed:", error.message, "\n");
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
console.log("✅ Claude Code setup complete!\n");
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function setupCodex(codexDir) {
|
|
177
|
+
console.log("═══════════════════════════════════════════════════════════════");
|
|
178
|
+
console.log(`🚀 Setting up ScPL Shortcuts for Codex at ${codexDir}...`);
|
|
179
|
+
console.log("═══════════════════════════════════════════════════════════════\n");
|
|
70
180
|
|
|
71
181
|
const codexConfigPath = join(codexDir, "config.toml");
|
|
72
182
|
const skillDir = join(codexDir, "skills", "scpl-shortcuts");
|
|
@@ -79,7 +189,6 @@ if (codexArg) {
|
|
|
79
189
|
config = readFileSync(codexConfigPath, "utf-8");
|
|
80
190
|
}
|
|
81
191
|
|
|
82
|
-
// Check if already configured
|
|
83
192
|
if (config.includes('[mcp_servers."scpl-shortcuts"]') || config.includes('[mcp_servers.scpl-shortcuts]')) {
|
|
84
193
|
console.log(" ⏭️ Already configured, skipping...\n");
|
|
85
194
|
} else {
|
|
@@ -93,14 +202,7 @@ startup_timeout_sec = 60.0
|
|
|
93
202
|
console.log(" ✅ MCP server added!\n");
|
|
94
203
|
}
|
|
95
204
|
} catch (error) {
|
|
96
|
-
console.error(" ❌ Failed
|
|
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
|
-
`);
|
|
205
|
+
console.error(" ❌ Failed:", error.message, "\n");
|
|
104
206
|
}
|
|
105
207
|
|
|
106
208
|
// Step 2: Install skill
|
|
@@ -110,243 +212,80 @@ startup_timeout_sec = 60.0
|
|
|
110
212
|
|
|
111
213
|
const skillContent = `---
|
|
112
214
|
name: scpl-shortcuts
|
|
113
|
-
description: Create macOS Shortcuts using natural language.
|
|
215
|
+
description: Create macOS Shortcuts using natural language.
|
|
114
216
|
metadata:
|
|
115
217
|
short-description: Create macOS Shortcuts with AI
|
|
116
218
|
---
|
|
117
219
|
|
|
118
220
|
# ScPL Shortcuts Skill
|
|
119
221
|
|
|
120
|
-
|
|
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 |
|
|
222
|
+
493 actions available. Tools: create_shortcut, validate_scpl, list_actions
|
|
131
223
|
|
|
132
224
|
## ScPL Syntax
|
|
133
|
-
|
|
134
|
-
ScPL is line-based. Each line is an action. Parameters use \`key=value\` or \`key="value"\`.
|
|
135
|
-
|
|
136
225
|
\`\`\`scpl
|
|
137
|
-
|
|
138
|
-
|
|
226
|
+
Text "Hello"
|
|
227
|
+
AskLLM model="Apple Intelligence" prompt="Make it fun"
|
|
139
228
|
ShowResult
|
|
140
|
-
|
|
141
|
-
# Variables
|
|
142
|
-
Text "some value"
|
|
143
|
-
SetVariable v:myVar
|
|
144
|
-
ShowResult v:myVar
|
|
145
|
-
|
|
146
|
-
# AI actions
|
|
147
|
-
AskLLM model="Apple Intelligence" prompt="Summarize this"
|
|
148
|
-
AskChatGPT prompt="Explain this"
|
|
149
229
|
\`\`\`
|
|
150
230
|
|
|
151
|
-
##
|
|
152
|
-
|
|
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
|
|
231
|
+
## Categories
|
|
232
|
+
AI, Clock, Voice Memos, System, Files, Scripting, Clipboard
|
|
160
233
|
|
|
161
234
|
## Workflow
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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
|
|
169
|
-
|
|
170
|
-
## Example: Timer with Notification
|
|
171
|
-
|
|
172
|
-
\`\`\`scpl
|
|
173
|
-
# Start a 25-minute Pomodoro timer
|
|
174
|
-
StartTimer minutes=25
|
|
175
|
-
ShowAlert title="Timer Started" message="Focus for 25 minutes!"
|
|
176
|
-
\`\`\`
|
|
177
|
-
|
|
178
|
-
## Example: Clipboard AI Enhancement
|
|
179
|
-
|
|
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
|
-
\`\`\`
|
|
235
|
+
1. Write ScPL code
|
|
236
|
+
2. validate_scpl to check
|
|
237
|
+
3. create_shortcut to generate .shortcut file
|
|
187
238
|
`;
|
|
188
239
|
writeFileSync(join(skillDir, "SKILL.md"), skillContent);
|
|
189
240
|
console.log(" ✅ Skill installed!\n");
|
|
190
241
|
} catch (error) {
|
|
191
|
-
console.error(" ❌ Failed
|
|
242
|
+
console.error(" ❌ Failed:", error.message, "\n");
|
|
192
243
|
}
|
|
193
244
|
|
|
194
|
-
console.log(
|
|
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);
|
|
245
|
+
console.log(`✅ Codex setup complete for ${codexDir}!\n`);
|
|
198
246
|
}
|
|
199
247
|
|
|
200
248
|
// ============================================================================
|
|
201
|
-
//
|
|
249
|
+
// PROCESS SETUP FLAGS
|
|
202
250
|
// ============================================================================
|
|
203
|
-
if (process.argv.includes("--setup")) {
|
|
204
|
-
console.log("🚀 Setting up ScPL Shortcuts for Claude Code...\n");
|
|
205
|
-
|
|
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");
|
|
209
|
-
|
|
210
|
-
// Step 1: Add MCP server to ~/.claude.json
|
|
211
|
-
console.log("📝 Step 1: Adding MCP server to ~/.claude.json...");
|
|
212
|
-
try {
|
|
213
|
-
let claudeConfig = {};
|
|
214
|
-
if (existsSync(claudeJsonPath)) {
|
|
215
|
-
claudeConfig = JSON.parse(readFileSync(claudeJsonPath, "utf-8"));
|
|
216
|
-
}
|
|
217
251
|
|
|
218
|
-
|
|
219
|
-
claudeConfig.mcpServers = {};
|
|
220
|
-
}
|
|
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
|
-
} 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`);
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
// Step 2: Create plugin directory and files
|
|
237
|
-
console.log("📁 Step 2: Installing plugin files...");
|
|
238
|
-
try {
|
|
239
|
-
mkdirSync(join(pluginsDir, "skills"), { recursive: true });
|
|
252
|
+
let didSetup = false;
|
|
240
253
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
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));
|
|
255
|
-
|
|
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]
|
|
260
|
-
---
|
|
261
|
-
|
|
262
|
-
# Create Shortcut Skill
|
|
263
|
-
|
|
264
|
-
You have access to the ScPL MCP server with 493 actions for creating macOS Shortcuts.
|
|
265
|
-
|
|
266
|
-
## Available Tools
|
|
267
|
-
|
|
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
|
|
271
|
-
|
|
272
|
-
## Popular Action Categories
|
|
273
|
-
|
|
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
|
|
280
|
-
|
|
281
|
-
## ScPL Syntax Examples
|
|
282
|
-
|
|
283
|
-
\`\`\`scpl
|
|
284
|
-
# Simple notification
|
|
285
|
-
ShowResult "Hello World!"
|
|
286
|
-
|
|
287
|
-
# Use Apple Intelligence
|
|
288
|
-
Text "Summarize this for me"
|
|
289
|
-
AskLLM model="Apple Intelligence" prompt="Make it shorter"
|
|
290
|
-
ShowResult
|
|
291
|
-
|
|
292
|
-
# Shell script
|
|
293
|
-
RunShellScript shell="/bin/zsh" script="echo Hello"
|
|
294
|
-
ShowResult
|
|
295
|
-
|
|
296
|
-
# Variables
|
|
297
|
-
Text "Hello"
|
|
298
|
-
SetVariable v:greeting
|
|
299
|
-
ShowResult v:greeting
|
|
300
|
-
\`\`\`
|
|
301
|
-
|
|
302
|
-
## Workflow
|
|
254
|
+
// Claude Code setup
|
|
255
|
+
if (process.argv.includes("--setup")) {
|
|
256
|
+
setupClaudeCode();
|
|
257
|
+
didSetup = true;
|
|
258
|
+
}
|
|
303
259
|
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
-
}
|
|
260
|
+
// Codex setups (can have multiple --setup-codex and --setup-codex=<dir>)
|
|
261
|
+
const codexArgs = process.argv.filter(arg => arg.startsWith("--setup-codex"));
|
|
262
|
+
for (const codexArg of codexArgs) {
|
|
263
|
+
let codexDir = join(homedir(), ".codex"); // default
|
|
316
264
|
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (existsSync(installedPluginsPath)) {
|
|
322
|
-
installedPlugins = JSON.parse(readFileSync(installedPluginsPath, "utf-8"));
|
|
265
|
+
if (codexArg.includes("=")) {
|
|
266
|
+
let customDir = codexArg.split("=")[1];
|
|
267
|
+
if (customDir.startsWith("~")) {
|
|
268
|
+
customDir = customDir.replace("~", homedir());
|
|
323
269
|
}
|
|
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");
|
|
270
|
+
codexDir = customDir;
|
|
340
271
|
}
|
|
341
272
|
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
273
|
+
setupCodex(codexDir);
|
|
274
|
+
didSetup = true;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Exit after setup(s)
|
|
278
|
+
if (didSetup) {
|
|
279
|
+
console.log("═══════════════════════════════════════════════════════════════");
|
|
280
|
+
console.log("🎉 All setups complete! Restart your AI tool(s) to use shortcuts.");
|
|
281
|
+
console.log("═══════════════════════════════════════════════════════════════");
|
|
282
|
+
console.log('\nUsage: Just ask to create a shortcut!');
|
|
283
|
+
console.log(' Example: "Create a shortcut that starts a timer"\n');
|
|
345
284
|
process.exit(0);
|
|
346
285
|
}
|
|
347
286
|
|
|
348
287
|
// ============================================================================
|
|
349
|
-
// MCP SERVER
|
|
288
|
+
// MCP SERVER (runs if no setup flags)
|
|
350
289
|
// ============================================================================
|
|
351
290
|
|
|
352
291
|
const server = new Server(
|
|
@@ -430,24 +369,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
430
369
|
if (name === "create_shortcut") {
|
|
431
370
|
const { scpl_code, output_name, output_dir } = args;
|
|
432
371
|
|
|
433
|
-
// Convert ScPL to shortcut
|
|
434
372
|
const shortcutBuffer = convert(scpl_code, {
|
|
435
373
|
makePlist: true,
|
|
436
374
|
makeShortcut: true,
|
|
437
375
|
});
|
|
438
376
|
|
|
439
|
-
// Determine output path (default to ~/Documents)
|
|
440
377
|
const dir = output_dir || join(homedir(), "Documents");
|
|
441
378
|
const outputPath = join(dir, `${output_name}.shortcut`);
|
|
442
379
|
|
|
443
|
-
// Write the file
|
|
444
380
|
writeFileSync(outputPath, shortcutBuffer);
|
|
445
381
|
|
|
446
382
|
return {
|
|
447
383
|
content: [
|
|
448
384
|
{
|
|
449
385
|
type: "text",
|
|
450
|
-
text: `✅ Shortcut created
|
|
386
|
+
text: `✅ Shortcut created!\n\nPath: ${outputPath}\n\nTo install: Drag onto Shortcut Source Helper from RoutineHub`,
|
|
451
387
|
},
|
|
452
388
|
],
|
|
453
389
|
};
|
|
@@ -457,69 +393,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
457
393
|
const { scpl_code } = args;
|
|
458
394
|
|
|
459
395
|
try {
|
|
460
|
-
convert(scpl_code, {
|
|
461
|
-
|
|
462
|
-
makeShortcut: false,
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
return {
|
|
466
|
-
content: [
|
|
467
|
-
{
|
|
468
|
-
type: "text",
|
|
469
|
-
text: "✅ ScPL code is valid!",
|
|
470
|
-
},
|
|
471
|
-
],
|
|
472
|
-
};
|
|
396
|
+
convert(scpl_code, { makePlist: false, makeShortcut: false });
|
|
397
|
+
return { content: [{ type: "text", text: "✅ ScPL code is valid!" }] };
|
|
473
398
|
} 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
|
-
};
|
|
399
|
+
return { content: [{ type: "text", text: `❌ Invalid: ${error.message}` }], isError: true };
|
|
483
400
|
}
|
|
484
401
|
}
|
|
485
402
|
|
|
486
403
|
if (name === "list_actions") {
|
|
487
404
|
const { category, search } = args || {};
|
|
488
405
|
|
|
489
|
-
// Embedded action list (top actions for quick reference)
|
|
490
406
|
const topActions = {
|
|
491
|
-
// AI
|
|
492
407
|
"is.workflow.actions.askllm": { Name: "Ask LLM", Category: "AI" },
|
|
493
408
|
"is.workflow.actions.askchatgpt": { Name: "Ask ChatGPT", Category: "AI" },
|
|
494
409
|
"com.anthropic.claudeforipad.AskClaudeIntentExtension": { Name: "Ask Claude", Category: "AI" },
|
|
495
|
-
// Clock
|
|
496
410
|
"com.apple.clock.StartStopwatchIntent": { Name: "Start Stopwatch", Category: "Clock" },
|
|
497
411
|
"com.apple.clock.StopStopwatchIntent": { Name: "Stop Stopwatch", Category: "Clock" },
|
|
498
412
|
"com.apple.clock.CreateAlarmIntent": { Name: "Create Alarm", Category: "Clock" },
|
|
499
|
-
// Voice Memos
|
|
500
413
|
"com.apple.VoiceMemos.CreateRecordingIntent": { Name: "Create Recording", Category: "Voice Memos" },
|
|
501
414
|
"com.apple.VoiceMemos.PlayRecordingIntent": { Name: "Play Recording", Category: "Voice Memos" },
|
|
502
|
-
// System
|
|
503
415
|
"is.workflow.actions.appearance": { Name: "Set Dark/Light Mode", Category: "System" },
|
|
504
416
|
"is.workflow.actions.takescreenshot": { Name: "Take Screenshot", Category: "System" },
|
|
505
417
|
"is.workflow.actions.lockscreen": { Name: "Lock Screen", Category: "System" },
|
|
506
|
-
// Scripting
|
|
507
418
|
"is.workflow.actions.runshellscript": { Name: "Run Shell Script", Category: "Scripting" },
|
|
508
419
|
"is.workflow.actions.runapplescript": { Name: "Run AppleScript", Category: "Scripting" },
|
|
509
420
|
"is.workflow.actions.runjavascriptforautomation": { Name: "Run JavaScript", Category: "Scripting" },
|
|
510
|
-
// Files
|
|
511
421
|
"is.workflow.actions.file.getfile": { Name: "Get File", Category: "Files" },
|
|
512
422
|
"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
423
|
"is.workflow.actions.showresult": { Name: "Show Result", Category: "Text" },
|
|
518
424
|
"is.workflow.actions.alert": { Name: "Show Alert", Category: "Text" },
|
|
519
|
-
// Variables
|
|
520
425
|
"is.workflow.actions.setvariable": { Name: "Set Variable", Category: "Variables" },
|
|
521
|
-
"is.workflow.actions.getvariable": { Name: "Get Variable", Category: "Variables" },
|
|
522
|
-
// Clipboard
|
|
523
426
|
"is.workflow.actions.getclipboard": { Name: "Get Clipboard", Category: "Clipboard" },
|
|
524
427
|
"is.workflow.actions.setclipboard": { Name: "Set Clipboard", Category: "Clipboard" },
|
|
525
428
|
};
|
|
@@ -527,108 +430,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
527
430
|
let filtered = Object.entries(topActions);
|
|
528
431
|
|
|
529
432
|
if (category) {
|
|
530
|
-
filtered = filtered.filter(
|
|
531
|
-
([_, action]) => action.Category?.toLowerCase() === category.toLowerCase()
|
|
532
|
-
);
|
|
433
|
+
filtered = filtered.filter(([_, a]) => a.Category?.toLowerCase() === category.toLowerCase());
|
|
533
434
|
}
|
|
534
|
-
|
|
535
435
|
if (search) {
|
|
536
|
-
const
|
|
537
|
-
filtered = filtered.filter(
|
|
538
|
-
(
|
|
539
|
-
id.toLowerCase().includes(searchLower) ||
|
|
540
|
-
action.Name?.toLowerCase().includes(searchLower) ||
|
|
541
|
-
action.Category?.toLowerCase().includes(searchLower)
|
|
436
|
+
const s = search.toLowerCase();
|
|
437
|
+
filtered = filtered.filter(([id, a]) =>
|
|
438
|
+
id.toLowerCase().includes(s) || a.Name?.toLowerCase().includes(s)
|
|
542
439
|
);
|
|
543
440
|
}
|
|
544
441
|
|
|
545
|
-
const results = filtered
|
|
546
|
-
|
|
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
|
-
};
|
|
442
|
+
const results = filtered.map(([id, a]) => `• **${a.Name}** - \`${id}\``).join("\n");
|
|
443
|
+
return { content: [{ type: "text", text: `${filtered.length} actions:\n\n${results}\n\n(493 total available)` }] };
|
|
557
444
|
}
|
|
558
445
|
|
|
559
446
|
throw new Error(`Unknown tool: ${name}`);
|
|
560
447
|
} catch (error) {
|
|
561
|
-
return {
|
|
562
|
-
content: [
|
|
563
|
-
{
|
|
564
|
-
type: "text",
|
|
565
|
-
text: `Error: ${error.message}`,
|
|
566
|
-
},
|
|
567
|
-
],
|
|
568
|
-
isError: true,
|
|
569
|
-
};
|
|
448
|
+
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
570
449
|
}
|
|
571
450
|
});
|
|
572
451
|
|
|
573
|
-
// Resource handlers
|
|
574
452
|
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
|
-
};
|
|
453
|
+
return { resources: [{ uri: "scpl://examples", name: "ScPL Examples", mimeType: "text/markdown" }] };
|
|
585
454
|
});
|
|
586
455
|
|
|
587
456
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
588
|
-
|
|
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
|
-
};
|
|
457
|
+
if (request.params.uri === "scpl://examples") {
|
|
458
|
+
return { contents: [{ uri: "scpl://examples", mimeType: "text/markdown", text: "# Examples\n\n```scpl\nShowResult \"Hello!\"\n```" }] };
|
|
626
459
|
}
|
|
627
|
-
|
|
628
|
-
throw new Error(`Unknown resource: ${uri}`);
|
|
460
|
+
throw new Error("Unknown resource");
|
|
629
461
|
});
|
|
630
462
|
|
|
631
|
-
// Start server
|
|
632
463
|
async function main() {
|
|
633
464
|
const transport = new StdioServerTransport();
|
|
634
465
|
await server.connect(transport);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "scpl-updated-mcp-server",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
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",
|