screenhand 0.4.7 → 0.4.9

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.
@@ -401,6 +401,16 @@ async function ensureCDP(overridePort) {
401
401
  const server = new McpServer({ name: "screenhand", version: "3.0.0" }, {
402
402
  instructions: `ScreenHand gives you native desktop control on macOS/Windows. 111 tools across 7 layers.
403
403
 
404
+ ## Prebuilt Knowledge (already loaded — no setup needed)
405
+ ScreenHand ships with EXPERT-level references, playbooks, and app maps for these apps. They load automatically when the app is detected — you do NOT need to learn or explore these:
406
+
407
+ **Apple-native apps:** Terminal, Mail, Finder, Calendar, Reminders, Keynote, Pages, Notes, Photos, Apple Music, WhatsApp, iOS Simulator (37 refs, 65 playbooks, 15 app maps)
408
+ **Web/Creative apps:** Figma, Discord, DaVinci Resolve, Canva, Instagram, X/Twitter, LinkedIn, YouTube, Reddit, Threads, Notion, n8n, DevTo, Google Flow, Codex Desktop
409
+
410
+ For Simulator specifically: 53 shortcuts, 37 flows, 16 playbooks (launch app, screenshot, Face ID, push notifications, permissions, location, dark mode, etc.), all simctl commands documented.
411
+
412
+ To check what's available: coverage_report(bundleId, appName) — if it shows selectors + flows, you're good to go. Skip learning.
413
+
404
414
  ## Quick Actions (1-2 steps, no setup)
405
415
  focus("com.apple.Notes") → ui_press("New Note") → type_text("hello") → key("cmd+s")
406
416
  browser_navigate("https://...") → browser_click("#btn") → browser_js("return ...")
@@ -190,6 +190,9 @@ export class CoverageAuditor {
190
190
  }
191
191
  loadReferences(bundleId) {
192
192
  const refs = [];
193
+ // Derive short name for matching: "com.apple.iphonesimulator" → "iphonesimulator"
194
+ const bundleParts = bundleId.split(".");
195
+ const shortName = (bundleParts[bundleParts.length - 1] ?? "").toLowerCase();
193
196
  try {
194
197
  const files = fs.readdirSync(this.referencesDir);
195
198
  for (const file of files) {
@@ -198,7 +201,10 @@ export class CoverageAuditor {
198
201
  try {
199
202
  const raw = fs.readFileSync(path.join(this.referencesDir, file), "utf-8");
200
203
  const ref = JSON.parse(raw);
201
- if (ref.bundleId === bundleId || ref.platform === bundleId) {
204
+ if (ref.bundleId === bundleId ||
205
+ ref.platform === bundleId ||
206
+ ref.platform?.toLowerCase() === shortName ||
207
+ ref.id?.toLowerCase() === shortName) {
202
208
  refs.push(ref);
203
209
  }
204
210
  }
@@ -214,6 +220,27 @@ export class CoverageAuditor {
214
220
  const bundleParts = bundleId.split(".");
215
221
  const shortName = (bundleParts[bundleParts.length - 1] ?? "").toLowerCase();
216
222
  const appNameLower = appName.toLowerCase();
223
+ // Also match by filename prefix (e.g. "simulator-launch-app.json" matches appName "Simulator")
224
+ const filenamePrefixes = [shortName, appNameLower];
225
+ // Find the platform name from reference files for cross-matching
226
+ // e.g. bundleId "com.apple.iphonesimulator" → platform "simulator" in reference
227
+ const refPlatforms = [];
228
+ try {
229
+ const refFiles = fs.readdirSync(this.referencesDir);
230
+ for (const file of refFiles) {
231
+ if (!file.endsWith(".json"))
232
+ continue;
233
+ try {
234
+ const raw = fs.readFileSync(path.join(this.referencesDir, file), "utf-8");
235
+ const ref = JSON.parse(raw);
236
+ if (ref.bundleId === bundleId && ref.platform) {
237
+ refPlatforms.push(ref.platform.toLowerCase());
238
+ }
239
+ }
240
+ catch { /* skip */ }
241
+ }
242
+ }
243
+ catch { /* dir not found */ }
217
244
  try {
218
245
  const files = fs.readdirSync(this.playbooksDir);
219
246
  for (const file of files) {
@@ -222,12 +249,16 @@ export class CoverageAuditor {
222
249
  try {
223
250
  const raw = fs.readFileSync(path.join(this.playbooksDir, file), "utf-8");
224
251
  const pb = JSON.parse(raw);
225
- // Match by bundleId (exact), platform name (case-insensitive), or app name
252
+ // Match by bundleId (exact), platform name (case-insensitive), app name, or ref platform
226
253
  const platformLower = (pb.platform ?? "").toLowerCase();
254
+ const fileBase = file.replace(".json", "").toLowerCase();
227
255
  if (pb.bundleId === bundleId ||
228
256
  platformLower === bundleId ||
229
257
  platformLower === shortName ||
230
- platformLower === appNameLower) {
258
+ platformLower === appNameLower ||
259
+ refPlatforms.includes(platformLower) ||
260
+ filenamePrefixes.some(p => fileBase.startsWith(p + "-")) ||
261
+ refPlatforms.some(rp => fileBase.startsWith(rp + "-"))) {
231
262
  playbooks.push(pb);
232
263
  }
233
264
  }
@@ -20,7 +20,7 @@
20
20
  "consistency": 6
21
21
  },
22
22
  "confidence": 0.13111111111111112,
23
- "lastValidated": "2026-03-25T10:15:29.651Z",
23
+ "lastValidated": "2026-03-25T10:23:29.084Z",
24
24
  "mapVersion": 1,
25
25
  "uiArchitecture": {
26
26
  "type": "other",
@@ -2849,7 +2849,7 @@
2849
2849
  "shortcutsUsed": 20,
2850
2850
  "playbooksExported": 0,
2851
2851
  "edgeCasesHandled": 2,
2852
- "lastRecomputed": "2026-03-25T10:15:18.462Z",
2852
+ "lastRecomputed": "2026-03-25T10:23:17.594Z",
2853
2853
  "visibilityConditions": [
2854
2854
  {
2855
2855
  "elementLabel": "iPhone 16 Plus",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "screenhand",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "mcpName": "io.github.manushi4/screenhand",
5
5
  "description": "Give AI eyes and hands on your desktop. ScreenHand is an open-source MCP server that lets Claude and other AI agents see your screen, click buttons, type text, and control any app on macOS and Windows.",
6
6
  "homepage": "https://screenhand.com",