screenhand 0.4.8 → 0.5.0
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/dist/mcp-desktop.js
CHANGED
|
@@ -531,17 +531,24 @@ const leaseManager = new LeaseManager(LOCK_DIR);
|
|
|
531
531
|
// Playbooks dir holds only executable step sequences for job_create
|
|
532
532
|
// Resolution order: local dev paths → npm dist paths → ~/.screenhand/ user paths
|
|
533
533
|
function resolveDataDir(name) {
|
|
534
|
-
|
|
534
|
+
const hasJson = (dir) => fs.existsSync(dir) && fs.readdirSync(dir).some(f => f.endsWith(".json"));
|
|
535
|
+
// 1. Local dev path (when running from source: references/, playbooks/)
|
|
535
536
|
const local = path.resolve(__dirname, name);
|
|
536
|
-
if (
|
|
537
|
+
if (hasJson(local))
|
|
537
538
|
return local;
|
|
538
|
-
|
|
539
|
-
// 2. npm dist path (when installed via npx/npm)
|
|
539
|
+
// 2. npm dist path — same level (dist-references/ next to dist/)
|
|
540
540
|
const dist = path.resolve(__dirname, `dist-${name}`);
|
|
541
|
-
if (
|
|
541
|
+
if (hasJson(dist))
|
|
542
542
|
return dist;
|
|
543
|
-
|
|
544
|
-
|
|
543
|
+
// 3. npm dist path — parent level (when __dirname is dist/, check ../dist-references/)
|
|
544
|
+
const parentDist = path.resolve(__dirname, "..", `dist-${name}`);
|
|
545
|
+
if (hasJson(parentDist))
|
|
546
|
+
return parentDist;
|
|
547
|
+
// 4. Parent level plain name (../references/)
|
|
548
|
+
const parentLocal = path.resolve(__dirname, "..", name);
|
|
549
|
+
if (hasJson(parentLocal))
|
|
550
|
+
return parentLocal;
|
|
551
|
+
// 5. User home path (always available for user-generated content)
|
|
545
552
|
const userDir = path.join(os.homedir(), ".screenhand", name);
|
|
546
553
|
if (!fs.existsSync(userDir)) {
|
|
547
554
|
fs.mkdirSync(userDir, { recursive: true });
|
|
@@ -563,6 +570,9 @@ const seedAppMapsDir = (() => {
|
|
|
563
570
|
const dist = path.resolve(__dirname, "dist-app-maps");
|
|
564
571
|
if (fs.existsSync(dist))
|
|
565
572
|
return dist;
|
|
573
|
+
const parentDist = path.resolve(__dirname, "..", "dist-app-maps");
|
|
574
|
+
if (fs.existsSync(parentDist))
|
|
575
|
+
return parentDist;
|
|
566
576
|
const local = path.resolve(__dirname, "seed-app-maps");
|
|
567
577
|
if (fs.existsSync(local))
|
|
568
578
|
return local;
|
|
@@ -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 ||
|
|
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
|
|
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:
|
|
23
|
+
"lastValidated": "2026-03-25T10:26:08.299Z",
|
|
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:
|
|
2852
|
+
"lastRecomputed": "2026-03-25T10:26:36.495Z",
|
|
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.
|
|
3
|
+
"version": "0.5.0",
|
|
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",
|