scpl-updated-mcp-server 1.0.3 ā 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 +190 -340
- 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";
|
|
@@ -29,160 +29,41 @@ USAGE:
|
|
|
29
29
|
npx scpl-updated-mcp-server [OPTIONS]
|
|
30
30
|
|
|
31
31
|
OPTIONS:
|
|
32
|
-
--setup
|
|
33
|
-
--setup-codex
|
|
34
|
-
--
|
|
32
|
+
--setup Auto-install for Claude Code
|
|
33
|
+
--setup-codex Auto-install for OpenAI Codex CLI (~/.codex)
|
|
34
|
+
--setup-codex=<dir> Auto-install for Codex forks with custom directory
|
|
35
|
+
--help, -h Show this help message
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
npx scpl-updated-mcp-server --setup
|
|
38
|
-
npx scpl-updated-mcp-server --setup-codex # Install for Codex
|
|
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
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
process.exit(0);
|
|
44
|
-
}
|
|
40
|
+
EXAMPLES:
|
|
41
|
+
# Claude Code only
|
|
42
|
+
npx scpl-updated-mcp-server --setup
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
// ============================================================================
|
|
49
|
-
if (process.argv.includes("--setup-codex")) {
|
|
50
|
-
console.log("š Setting up ScPL Shortcuts for Codex...\n");
|
|
44
|
+
# Codex only
|
|
45
|
+
npx scpl-updated-mcp-server --setup-codex
|
|
51
46
|
|
|
52
|
-
|
|
53
|
-
|
|
47
|
+
# Custom Codex directory (just-every/code, etc.)
|
|
48
|
+
npx scpl-updated-mcp-server --setup-codex=$CODE_HOME
|
|
54
49
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
let config = "";
|
|
59
|
-
if (existsSync(codexConfigPath)) {
|
|
60
|
-
config = readFileSync(codexConfigPath, "utf-8");
|
|
61
|
-
}
|
|
50
|
+
# All at once: Claude + Codex + custom fork
|
|
51
|
+
npx scpl-updated-mcp-server --setup --setup-codex --setup-codex=~/.code
|
|
62
52
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
console.log(" āļø Already configured, skipping...\n");
|
|
66
|
-
} else {
|
|
67
|
-
const tomlBlock = `
|
|
68
|
-
[mcp_servers.scpl-shortcuts]
|
|
69
|
-
command = "npx"
|
|
70
|
-
args = ["-y", "scpl-updated-mcp-server"]
|
|
71
|
-
startup_timeout_sec = 60.0
|
|
72
|
-
`;
|
|
73
|
-
writeFileSync(codexConfigPath, config + tomlBlock);
|
|
74
|
-
console.log(" ā
MCP server added!\n");
|
|
75
|
-
}
|
|
76
|
-
} catch (error) {
|
|
77
|
-
console.error(" ā Failed to update config:", error.message);
|
|
78
|
-
console.log(" Add this to ~/.codex/config.toml manually:");
|
|
79
|
-
console.log(`
|
|
80
|
-
[mcp_servers.scpl-shortcuts]
|
|
81
|
-
command = "npx"
|
|
82
|
-
args = ["-y", "scpl-updated-mcp-server"]
|
|
83
|
-
startup_timeout_sec = 60.0
|
|
53
|
+
After setup, restart your AI coding tool and ask:
|
|
54
|
+
"Create a shortcut that starts a timer and plays a sound"
|
|
84
55
|
`);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// Step 2: Install skill to ~/.codex/skills/scpl-shortcuts/
|
|
88
|
-
console.log("š Step 2: Installing skill to ~/.codex/skills/scpl-shortcuts/...");
|
|
89
|
-
try {
|
|
90
|
-
mkdirSync(skillDir, { recursive: true });
|
|
91
|
-
|
|
92
|
-
const skillContent = `---
|
|
93
|
-
name: scpl-shortcuts
|
|
94
|
-
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.
|
|
95
|
-
metadata:
|
|
96
|
-
short-description: Create macOS Shortcuts with AI
|
|
97
|
-
---
|
|
98
|
-
|
|
99
|
-
# ScPL Shortcuts Skill
|
|
100
|
-
|
|
101
|
-
Create macOS Shortcuts using natural language with 493 available actions.
|
|
102
|
-
|
|
103
|
-
## MCP Tools Available
|
|
104
|
-
|
|
105
|
-
You have access to the \`scpl-shortcuts\` MCP server with these tools:
|
|
106
|
-
|
|
107
|
-
| Tool | Description |
|
|
108
|
-
|------|-------------|
|
|
109
|
-
| \`create_shortcut\` | Generate a .shortcut file from ScPL code |
|
|
110
|
-
| \`validate_scpl\` | Check if ScPL code is valid before creating |
|
|
111
|
-
| \`list_actions\` | Search available actions by category or keyword |
|
|
112
|
-
|
|
113
|
-
## ScPL Syntax
|
|
114
|
-
|
|
115
|
-
ScPL is line-based. Each line is an action. Parameters use \`key=value\` or \`key="value"\`.
|
|
116
|
-
|
|
117
|
-
\`\`\`scpl
|
|
118
|
-
# Comments start with #
|
|
119
|
-
Text "Hello World"
|
|
120
|
-
ShowResult
|
|
121
|
-
|
|
122
|
-
# Variables
|
|
123
|
-
Text "some value"
|
|
124
|
-
SetVariable v:myVar
|
|
125
|
-
ShowResult v:myVar
|
|
126
|
-
|
|
127
|
-
# AI actions
|
|
128
|
-
AskLLM model="Apple Intelligence" prompt="Summarize this"
|
|
129
|
-
AskChatGPT prompt="Explain this"
|
|
130
|
-
\`\`\`
|
|
131
|
-
|
|
132
|
-
## Popular Actions by Category
|
|
133
|
-
|
|
134
|
-
**AI**: AskLLM, AskChatGPT, AskClaude
|
|
135
|
-
**Clock**: StartStopwatch, StopStopwatch, CreateAlarm
|
|
136
|
-
**Voice Memos**: CreateRecording, PlayRecording
|
|
137
|
-
**System**: SetDarkMode, TakeScreenshot, LockScreen
|
|
138
|
-
**Files**: GetFile, SaveFile, RenameFile, RevealInFinder
|
|
139
|
-
**Scripting**: RunShellScript, RunAppleScript, RunJavaScriptForAutomation
|
|
140
|
-
**Clipboard**: GetClipboard, SetClipboard
|
|
141
|
-
|
|
142
|
-
## Workflow
|
|
143
|
-
|
|
144
|
-
1. User describes what shortcut they want
|
|
145
|
-
2. Use \`list_actions\` if you need to find specific actions
|
|
146
|
-
3. Write ScPL code for the shortcut
|
|
147
|
-
4. Use \`validate_scpl\` to check syntax
|
|
148
|
-
5. Use \`create_shortcut\` to generate the .shortcut file
|
|
149
|
-
6. Tell user to install via Shortcut Source Helper from RoutineHub
|
|
150
|
-
|
|
151
|
-
## Example: Timer with Notification
|
|
152
|
-
|
|
153
|
-
\`\`\`scpl
|
|
154
|
-
# Start a 25-minute Pomodoro timer
|
|
155
|
-
StartTimer minutes=25
|
|
156
|
-
ShowAlert title="Timer Started" message="Focus for 25 minutes!"
|
|
157
|
-
\`\`\`
|
|
158
|
-
|
|
159
|
-
## Example: Clipboard AI Enhancement
|
|
160
|
-
|
|
161
|
-
\`\`\`scpl
|
|
162
|
-
GetClipboard
|
|
163
|
-
SetVariable v:text
|
|
164
|
-
AskChatGPT prompt="Improve this text: \\(v:text)"
|
|
165
|
-
SetClipboard
|
|
166
|
-
ShowAlert title="Done" message="Improved text copied!"
|
|
167
|
-
\`\`\`
|
|
168
|
-
`;
|
|
169
|
-
writeFileSync(join(skillDir, "SKILL.md"), skillContent);
|
|
170
|
-
console.log(" ā
Skill installed!\n");
|
|
171
|
-
} catch (error) {
|
|
172
|
-
console.error(" ā Failed to install skill:", error.message, "\n");
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
console.log("š Setup complete! Restart Codex to use the shortcuts tools.\n");
|
|
176
|
-
console.log("Usage: Just ask Codex to create a shortcut!");
|
|
177
|
-
console.log(' Example: "Create a shortcut that starts a timer and plays a sound"\n');
|
|
178
56
|
process.exit(0);
|
|
179
57
|
}
|
|
180
58
|
|
|
181
59
|
// ============================================================================
|
|
182
|
-
//
|
|
60
|
+
// SETUP FUNCTIONS
|
|
183
61
|
// ============================================================================
|
|
184
|
-
|
|
185
|
-
|
|
62
|
+
|
|
63
|
+
function setupClaudeCode() {
|
|
64
|
+
console.log("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā");
|
|
65
|
+
console.log("š Setting up ScPL Shortcuts for Claude Code...");
|
|
66
|
+
console.log("āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā\n");
|
|
186
67
|
|
|
187
68
|
const claudeJsonPath = join(homedir(), ".claude.json");
|
|
188
69
|
const pluginsDir = join(homedir(), ".claude", "plugins", "local", "scpl-shortcuts");
|
|
@@ -200,18 +81,19 @@ if (process.argv.includes("--setup")) {
|
|
|
200
81
|
claudeConfig.mcpServers = {};
|
|
201
82
|
}
|
|
202
83
|
|
|
203
|
-
claudeConfig.mcpServers["scpl-shortcuts"]
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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
|
+
}
|
|
211
95
|
} catch (error) {
|
|
212
|
-
console.error(" ā Failed
|
|
213
|
-
console.log(" You can manually add this to ~/.claude.json under mcpServers:");
|
|
214
|
-
console.log(` "scpl-shortcuts": { "type": "stdio", "command": "npx", "args": ["-y", "scpl-updated-mcp-server"] }\n`);
|
|
96
|
+
console.error(" ā Failed:", error.message, "\n");
|
|
215
97
|
}
|
|
216
98
|
|
|
217
99
|
// Step 2: Create plugin directory and files
|
|
@@ -219,7 +101,6 @@ if (process.argv.includes("--setup")) {
|
|
|
219
101
|
try {
|
|
220
102
|
mkdirSync(join(pluginsDir, "skills"), { recursive: true });
|
|
221
103
|
|
|
222
|
-
// Write plugin.json
|
|
223
104
|
const pluginJson = {
|
|
224
105
|
name: "scpl-shortcuts",
|
|
225
106
|
version: "1.0.0",
|
|
@@ -227,75 +108,41 @@ if (process.argv.includes("--setup")) {
|
|
|
227
108
|
skills: [
|
|
228
109
|
{
|
|
229
110
|
name: "create-shortcut",
|
|
230
|
-
description: "Create a macOS Shortcut using natural language.
|
|
111
|
+
description: "Create a macOS Shortcut using natural language.",
|
|
231
112
|
path: "skills/create-shortcut.md"
|
|
232
113
|
}
|
|
233
114
|
]
|
|
234
115
|
};
|
|
235
116
|
writeFileSync(join(pluginsDir, "plugin.json"), JSON.stringify(pluginJson, null, 2));
|
|
236
117
|
|
|
237
|
-
// Write skill file
|
|
238
118
|
const skillContent = `---
|
|
239
|
-
description: Create macOS Shortcuts using natural language.
|
|
119
|
+
description: Create macOS Shortcuts using natural language.
|
|
240
120
|
tags: [shortcuts, automation, macos, scpl]
|
|
241
121
|
---
|
|
242
122
|
|
|
243
123
|
# Create Shortcut Skill
|
|
244
124
|
|
|
245
|
-
You have access to the ScPL MCP server with 493 actions
|
|
125
|
+
You have access to the ScPL MCP server with 493 actions.
|
|
246
126
|
|
|
247
|
-
##
|
|
248
|
-
|
|
249
|
-
1. **create_shortcut** - Generate a .shortcut file from ScPL code
|
|
250
|
-
2. **validate_scpl** - Check if ScPL code is valid before creating
|
|
251
|
-
3. **list_actions** - Search available actions by category or keyword
|
|
252
|
-
|
|
253
|
-
## Popular Action Categories
|
|
254
|
-
|
|
255
|
-
- **AI**: AskLLM (Apple Intelligence), AskChatGPT, AskClaude
|
|
256
|
-
- **Clock**: StartStopwatch, CreateAlarm, GetCurrentTime
|
|
257
|
-
- **Voice Memos**: CreateRecording, PlayRecording
|
|
258
|
-
- **System**: SetDarkMode, TakeScreenshot, LockScreen
|
|
259
|
-
- **Files**: GetFile, SaveFile, RenameFile, RevealInFinder
|
|
260
|
-
- **Scripting**: RunShellScript, RunAppleScript
|
|
261
|
-
|
|
262
|
-
## ScPL Syntax Examples
|
|
127
|
+
## Tools: create_shortcut, validate_scpl, list_actions
|
|
263
128
|
|
|
129
|
+
## ScPL Syntax
|
|
264
130
|
\`\`\`scpl
|
|
265
|
-
# Simple notification
|
|
266
|
-
ShowResult "Hello World!"
|
|
267
|
-
|
|
268
|
-
# Use Apple Intelligence
|
|
269
|
-
Text "Summarize this for me"
|
|
270
|
-
AskLLM model="Apple Intelligence" prompt="Make it shorter"
|
|
271
|
-
ShowResult
|
|
272
|
-
|
|
273
|
-
# Shell script
|
|
274
|
-
RunShellScript shell="/bin/zsh" script="echo Hello"
|
|
275
|
-
ShowResult
|
|
276
|
-
|
|
277
|
-
# Variables
|
|
278
131
|
Text "Hello"
|
|
279
|
-
|
|
280
|
-
ShowResult
|
|
132
|
+
AskLLM model="Apple Intelligence" prompt="Make it fun"
|
|
133
|
+
ShowResult
|
|
281
134
|
\`\`\`
|
|
282
135
|
|
|
283
|
-
##
|
|
284
|
-
|
|
285
|
-
1. User describes what they want
|
|
286
|
-
2. Use \`list_actions\` if you need to find specific actions
|
|
287
|
-
3. Write ScPL code for the shortcut
|
|
288
|
-
4. Use \`validate_scpl\` to check syntax
|
|
289
|
-
5. Use \`create_shortcut\` to generate the .shortcut file
|
|
290
|
-
6. Tell user to drag the file onto Shortcut Source Helper to install
|
|
136
|
+
## Categories
|
|
137
|
+
AI, Clock, Voice Memos, System, Files, Scripting, Clipboard
|
|
291
138
|
`;
|
|
292
139
|
writeFileSync(join(pluginsDir, "skills", "create-shortcut.md"), skillContent);
|
|
293
140
|
console.log(" ā
Plugin files created!\n");
|
|
294
141
|
} catch (error) {
|
|
295
|
-
console.error(" ā Failed
|
|
142
|
+
console.error(" ā Failed:", error.message, "\n");
|
|
296
143
|
}
|
|
297
144
|
|
|
298
|
-
// Step 3: Register plugin
|
|
145
|
+
// Step 3: Register plugin
|
|
299
146
|
console.log("š Step 3: Registering plugin...");
|
|
300
147
|
try {
|
|
301
148
|
let installedPlugins = { version: 2, plugins: {} };
|
|
@@ -303,31 +150,142 @@ ShowResult v:greeting
|
|
|
303
150
|
installedPlugins = JSON.parse(readFileSync(installedPluginsPath, "utf-8"));
|
|
304
151
|
}
|
|
305
152
|
|
|
306
|
-
installedPlugins.plugins["scpl-shortcuts@local"]
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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");
|
|
180
|
+
|
|
181
|
+
const codexConfigPath = join(codexDir, "config.toml");
|
|
182
|
+
const skillDir = join(codexDir, "skills", "scpl-shortcuts");
|
|
183
|
+
|
|
184
|
+
// Step 1: Add MCP server to config.toml
|
|
185
|
+
console.log(`š Step 1: Adding MCP server to ${codexConfigPath}...`);
|
|
186
|
+
try {
|
|
187
|
+
let config = "";
|
|
188
|
+
if (existsSync(codexConfigPath)) {
|
|
189
|
+
config = readFileSync(codexConfigPath, "utf-8");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
if (config.includes('[mcp_servers."scpl-shortcuts"]') || config.includes('[mcp_servers.scpl-shortcuts]')) {
|
|
193
|
+
console.log(" āļø Already configured, skipping...\n");
|
|
194
|
+
} else {
|
|
195
|
+
const tomlBlock = `
|
|
196
|
+
[mcp_servers.scpl-shortcuts]
|
|
197
|
+
command = "npx"
|
|
198
|
+
args = ["-y", "scpl-updated-mcp-server"]
|
|
199
|
+
startup_timeout_sec = 60.0
|
|
200
|
+
`;
|
|
201
|
+
writeFileSync(codexConfigPath, config + tomlBlock);
|
|
202
|
+
console.log(" ā
MCP server added!\n");
|
|
203
|
+
}
|
|
204
|
+
} catch (error) {
|
|
205
|
+
console.error(" ā Failed:", error.message, "\n");
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Step 2: Install skill
|
|
209
|
+
console.log(`š Step 2: Installing skill to ${skillDir}...`);
|
|
210
|
+
try {
|
|
211
|
+
mkdirSync(skillDir, { recursive: true });
|
|
212
|
+
|
|
213
|
+
const skillContent = `---
|
|
214
|
+
name: scpl-shortcuts
|
|
215
|
+
description: Create macOS Shortcuts using natural language.
|
|
216
|
+
metadata:
|
|
217
|
+
short-description: Create macOS Shortcuts with AI
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
# ScPL Shortcuts Skill
|
|
221
|
+
|
|
222
|
+
493 actions available. Tools: create_shortcut, validate_scpl, list_actions
|
|
316
223
|
|
|
317
|
-
|
|
318
|
-
|
|
224
|
+
## ScPL Syntax
|
|
225
|
+
\`\`\`scpl
|
|
226
|
+
Text "Hello"
|
|
227
|
+
AskLLM model="Apple Intelligence" prompt="Make it fun"
|
|
228
|
+
ShowResult
|
|
229
|
+
\`\`\`
|
|
230
|
+
|
|
231
|
+
## Categories
|
|
232
|
+
AI, Clock, Voice Memos, System, Files, Scripting, Clipboard
|
|
233
|
+
|
|
234
|
+
## Workflow
|
|
235
|
+
1. Write ScPL code
|
|
236
|
+
2. validate_scpl to check
|
|
237
|
+
3. create_shortcut to generate .shortcut file
|
|
238
|
+
`;
|
|
239
|
+
writeFileSync(join(skillDir, "SKILL.md"), skillContent);
|
|
240
|
+
console.log(" ā
Skill installed!\n");
|
|
319
241
|
} catch (error) {
|
|
320
|
-
console.error(" ā Failed
|
|
242
|
+
console.error(" ā Failed:", error.message, "\n");
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
console.log(`ā
Codex setup complete for ${codexDir}!\n`);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// ============================================================================
|
|
249
|
+
// PROCESS SETUP FLAGS
|
|
250
|
+
// ============================================================================
|
|
251
|
+
|
|
252
|
+
let didSetup = false;
|
|
253
|
+
|
|
254
|
+
// Claude Code setup
|
|
255
|
+
if (process.argv.includes("--setup")) {
|
|
256
|
+
setupClaudeCode();
|
|
257
|
+
didSetup = true;
|
|
258
|
+
}
|
|
259
|
+
|
|
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
|
|
264
|
+
|
|
265
|
+
if (codexArg.includes("=")) {
|
|
266
|
+
let customDir = codexArg.split("=")[1];
|
|
267
|
+
if (customDir.startsWith("~")) {
|
|
268
|
+
customDir = customDir.replace("~", homedir());
|
|
269
|
+
}
|
|
270
|
+
codexDir = customDir;
|
|
321
271
|
}
|
|
322
272
|
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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');
|
|
326
284
|
process.exit(0);
|
|
327
285
|
}
|
|
328
286
|
|
|
329
287
|
// ============================================================================
|
|
330
|
-
// MCP SERVER
|
|
288
|
+
// MCP SERVER (runs if no setup flags)
|
|
331
289
|
// ============================================================================
|
|
332
290
|
|
|
333
291
|
const server = new Server(
|
|
@@ -411,24 +369,21 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
411
369
|
if (name === "create_shortcut") {
|
|
412
370
|
const { scpl_code, output_name, output_dir } = args;
|
|
413
371
|
|
|
414
|
-
// Convert ScPL to shortcut
|
|
415
372
|
const shortcutBuffer = convert(scpl_code, {
|
|
416
373
|
makePlist: true,
|
|
417
374
|
makeShortcut: true,
|
|
418
375
|
});
|
|
419
376
|
|
|
420
|
-
// Determine output path (default to ~/Documents)
|
|
421
377
|
const dir = output_dir || join(homedir(), "Documents");
|
|
422
378
|
const outputPath = join(dir, `${output_name}.shortcut`);
|
|
423
379
|
|
|
424
|
-
// Write the file
|
|
425
380
|
writeFileSync(outputPath, shortcutBuffer);
|
|
426
381
|
|
|
427
382
|
return {
|
|
428
383
|
content: [
|
|
429
384
|
{
|
|
430
385
|
type: "text",
|
|
431
|
-
text: `ā
Shortcut created
|
|
386
|
+
text: `ā
Shortcut created!\n\nPath: ${outputPath}\n\nTo install: Drag onto Shortcut Source Helper from RoutineHub`,
|
|
432
387
|
},
|
|
433
388
|
],
|
|
434
389
|
};
|
|
@@ -438,69 +393,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
438
393
|
const { scpl_code } = args;
|
|
439
394
|
|
|
440
395
|
try {
|
|
441
|
-
convert(scpl_code, {
|
|
442
|
-
|
|
443
|
-
makeShortcut: false,
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
return {
|
|
447
|
-
content: [
|
|
448
|
-
{
|
|
449
|
-
type: "text",
|
|
450
|
-
text: "ā
ScPL code is valid!",
|
|
451
|
-
},
|
|
452
|
-
],
|
|
453
|
-
};
|
|
396
|
+
convert(scpl_code, { makePlist: false, makeShortcut: false });
|
|
397
|
+
return { content: [{ type: "text", text: "ā
ScPL code is valid!" }] };
|
|
454
398
|
} catch (error) {
|
|
455
|
-
return {
|
|
456
|
-
content: [
|
|
457
|
-
{
|
|
458
|
-
type: "text",
|
|
459
|
-
text: `ā ScPL validation failed:\n\n${error.message}`,
|
|
460
|
-
},
|
|
461
|
-
],
|
|
462
|
-
isError: true,
|
|
463
|
-
};
|
|
399
|
+
return { content: [{ type: "text", text: `ā Invalid: ${error.message}` }], isError: true };
|
|
464
400
|
}
|
|
465
401
|
}
|
|
466
402
|
|
|
467
403
|
if (name === "list_actions") {
|
|
468
404
|
const { category, search } = args || {};
|
|
469
405
|
|
|
470
|
-
// Embedded action list (top actions for quick reference)
|
|
471
406
|
const topActions = {
|
|
472
|
-
// AI
|
|
473
407
|
"is.workflow.actions.askllm": { Name: "Ask LLM", Category: "AI" },
|
|
474
408
|
"is.workflow.actions.askchatgpt": { Name: "Ask ChatGPT", Category: "AI" },
|
|
475
409
|
"com.anthropic.claudeforipad.AskClaudeIntentExtension": { Name: "Ask Claude", Category: "AI" },
|
|
476
|
-
// Clock
|
|
477
410
|
"com.apple.clock.StartStopwatchIntent": { Name: "Start Stopwatch", Category: "Clock" },
|
|
478
411
|
"com.apple.clock.StopStopwatchIntent": { Name: "Stop Stopwatch", Category: "Clock" },
|
|
479
412
|
"com.apple.clock.CreateAlarmIntent": { Name: "Create Alarm", Category: "Clock" },
|
|
480
|
-
// Voice Memos
|
|
481
413
|
"com.apple.VoiceMemos.CreateRecordingIntent": { Name: "Create Recording", Category: "Voice Memos" },
|
|
482
414
|
"com.apple.VoiceMemos.PlayRecordingIntent": { Name: "Play Recording", Category: "Voice Memos" },
|
|
483
|
-
// System
|
|
484
415
|
"is.workflow.actions.appearance": { Name: "Set Dark/Light Mode", Category: "System" },
|
|
485
416
|
"is.workflow.actions.takescreenshot": { Name: "Take Screenshot", Category: "System" },
|
|
486
417
|
"is.workflow.actions.lockscreen": { Name: "Lock Screen", Category: "System" },
|
|
487
|
-
// Scripting
|
|
488
418
|
"is.workflow.actions.runshellscript": { Name: "Run Shell Script", Category: "Scripting" },
|
|
489
419
|
"is.workflow.actions.runapplescript": { Name: "Run AppleScript", Category: "Scripting" },
|
|
490
420
|
"is.workflow.actions.runjavascriptforautomation": { Name: "Run JavaScript", Category: "Scripting" },
|
|
491
|
-
// Files
|
|
492
421
|
"is.workflow.actions.file.getfile": { Name: "Get File", Category: "Files" },
|
|
493
422
|
"is.workflow.actions.file.savefile": { Name: "Save File", Category: "Files" },
|
|
494
|
-
"is.workflow.actions.file.renamefile": { Name: "Rename File", Category: "Files" },
|
|
495
|
-
"is.workflow.actions.file.revealfile": { Name: "Reveal in Finder", Category: "Files" },
|
|
496
|
-
// Text
|
|
497
|
-
"is.workflow.actions.gettext": { Name: "Get Text", Category: "Text" },
|
|
498
423
|
"is.workflow.actions.showresult": { Name: "Show Result", Category: "Text" },
|
|
499
424
|
"is.workflow.actions.alert": { Name: "Show Alert", Category: "Text" },
|
|
500
|
-
// Variables
|
|
501
425
|
"is.workflow.actions.setvariable": { Name: "Set Variable", Category: "Variables" },
|
|
502
|
-
"is.workflow.actions.getvariable": { Name: "Get Variable", Category: "Variables" },
|
|
503
|
-
// Clipboard
|
|
504
426
|
"is.workflow.actions.getclipboard": { Name: "Get Clipboard", Category: "Clipboard" },
|
|
505
427
|
"is.workflow.actions.setclipboard": { Name: "Set Clipboard", Category: "Clipboard" },
|
|
506
428
|
};
|
|
@@ -508,108 +430,36 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
|
508
430
|
let filtered = Object.entries(topActions);
|
|
509
431
|
|
|
510
432
|
if (category) {
|
|
511
|
-
filtered = filtered.filter(
|
|
512
|
-
([_, action]) => action.Category?.toLowerCase() === category.toLowerCase()
|
|
513
|
-
);
|
|
433
|
+
filtered = filtered.filter(([_, a]) => a.Category?.toLowerCase() === category.toLowerCase());
|
|
514
434
|
}
|
|
515
|
-
|
|
516
435
|
if (search) {
|
|
517
|
-
const
|
|
518
|
-
filtered = filtered.filter(
|
|
519
|
-
(
|
|
520
|
-
id.toLowerCase().includes(searchLower) ||
|
|
521
|
-
action.Name?.toLowerCase().includes(searchLower) ||
|
|
522
|
-
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)
|
|
523
439
|
);
|
|
524
440
|
}
|
|
525
441
|
|
|
526
|
-
const results = filtered
|
|
527
|
-
|
|
528
|
-
.join("\n");
|
|
529
|
-
|
|
530
|
-
return {
|
|
531
|
-
content: [
|
|
532
|
-
{
|
|
533
|
-
type: "text",
|
|
534
|
-
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`,
|
|
535
|
-
},
|
|
536
|
-
],
|
|
537
|
-
};
|
|
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)` }] };
|
|
538
444
|
}
|
|
539
445
|
|
|
540
446
|
throw new Error(`Unknown tool: ${name}`);
|
|
541
447
|
} catch (error) {
|
|
542
|
-
return {
|
|
543
|
-
content: [
|
|
544
|
-
{
|
|
545
|
-
type: "text",
|
|
546
|
-
text: `Error: ${error.message}`,
|
|
547
|
-
},
|
|
548
|
-
],
|
|
549
|
-
isError: true,
|
|
550
|
-
};
|
|
448
|
+
return { content: [{ type: "text", text: `Error: ${error.message}` }], isError: true };
|
|
551
449
|
}
|
|
552
450
|
});
|
|
553
451
|
|
|
554
|
-
// Resource handlers
|
|
555
452
|
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
556
|
-
return {
|
|
557
|
-
resources: [
|
|
558
|
-
{
|
|
559
|
-
uri: "scpl://examples",
|
|
560
|
-
name: "ScPL Examples",
|
|
561
|
-
description: "Example shortcuts written in ScPL",
|
|
562
|
-
mimeType: "text/markdown",
|
|
563
|
-
},
|
|
564
|
-
],
|
|
565
|
-
};
|
|
453
|
+
return { resources: [{ uri: "scpl://examples", name: "ScPL Examples", mimeType: "text/markdown" }] };
|
|
566
454
|
});
|
|
567
455
|
|
|
568
456
|
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
if (uri === "scpl://examples") {
|
|
572
|
-
const examples = `# ScPL Examples
|
|
573
|
-
|
|
574
|
-
## Apple Intelligence
|
|
575
|
-
\`\`\`scpl
|
|
576
|
-
Text "Summarize this document"
|
|
577
|
-
AskLLM model="Apple Intelligence" prompt="Make it concise"
|
|
578
|
-
ShowResult
|
|
579
|
-
\`\`\`
|
|
580
|
-
|
|
581
|
-
## Timer with Sound
|
|
582
|
-
\`\`\`scpl
|
|
583
|
-
# Start a 5-minute timer
|
|
584
|
-
StartTimer minutes=5
|
|
585
|
-
ShowAlert title="Timer Started" message="5 minutes"
|
|
586
|
-
\`\`\`
|
|
587
|
-
|
|
588
|
-
## Shell Script
|
|
589
|
-
\`\`\`scpl
|
|
590
|
-
RunShellScript shell="/bin/zsh" script="echo Hello World"
|
|
591
|
-
ShowResult
|
|
592
|
-
\`\`\`
|
|
593
|
-
|
|
594
|
-
## Clipboard Workflow
|
|
595
|
-
\`\`\`scpl
|
|
596
|
-
GetClipboard
|
|
597
|
-
SetVariable v:text
|
|
598
|
-
AskChatGPT prompt="Improve this: \\(v:text)"
|
|
599
|
-
SetClipboard
|
|
600
|
-
ShowAlert title="Done" message="Improved text copied!"
|
|
601
|
-
\`\`\`
|
|
602
|
-
`;
|
|
603
|
-
|
|
604
|
-
return {
|
|
605
|
-
contents: [{ uri, mimeType: "text/markdown", text: examples }],
|
|
606
|
-
};
|
|
457
|
+
if (request.params.uri === "scpl://examples") {
|
|
458
|
+
return { contents: [{ uri: "scpl://examples", mimeType: "text/markdown", text: "# Examples\n\n```scpl\nShowResult \"Hello!\"\n```" }] };
|
|
607
459
|
}
|
|
608
|
-
|
|
609
|
-
throw new Error(`Unknown resource: ${uri}`);
|
|
460
|
+
throw new Error("Unknown resource");
|
|
610
461
|
});
|
|
611
462
|
|
|
612
|
-
// Start server
|
|
613
463
|
async function main() {
|
|
614
464
|
const transport = new StdioServerTransport();
|
|
615
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",
|