@harusame64/desktop-touch-mcp 0.15.7 → 1.0.3
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/LICENSE +21 -21
- package/README.ja.md +616 -516
- package/README.md +781 -685
- package/bin/launcher.js +83 -7
- package/package.json +79 -78
package/bin/launcher.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { execFile, spawn } from "node:child_process";
|
|
4
4
|
import { createReadStream, createWriteStream, existsSync } from "node:fs";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
5
6
|
import {
|
|
6
7
|
mkdir,
|
|
7
8
|
mkdtemp,
|
|
@@ -17,15 +18,15 @@ import path from "node:path";
|
|
|
17
18
|
import { Readable } from "node:stream";
|
|
18
19
|
import { pipeline } from "node:stream/promises";
|
|
19
20
|
|
|
20
|
-
const PACKAGE_VERSION = "0.
|
|
21
|
+
const PACKAGE_VERSION = "1.0.3";
|
|
21
22
|
const RELEASE_TAG = `v${PACKAGE_VERSION}`;
|
|
22
23
|
const REPO_API_URL = `https://api.github.com/repos/Harusame64/desktop-touch-mcp/releases/tags/${RELEASE_TAG}`;
|
|
23
24
|
const ASSET_NAME = "desktop-touch-mcp-windows.zip";
|
|
24
25
|
const RELEASE_METADATA_FILE = ".desktop-touch-release.json";
|
|
25
26
|
const RELEASE_MANIFEST = {
|
|
26
|
-
tagName: "
|
|
27
|
+
tagName: "v1.0.3",
|
|
27
28
|
assetName: ASSET_NAME,
|
|
28
|
-
sha256: "
|
|
29
|
+
sha256: "f019db6e0194dcf09f7428e8e42af7902de6f842695568eb7897750803d0807e",
|
|
29
30
|
};
|
|
30
31
|
const CACHE_ROOT = process.env.DESKTOP_TOUCH_MCP_HOME
|
|
31
32
|
? path.resolve(process.env.DESKTOP_TOUCH_MCP_HOME)
|
|
@@ -42,6 +43,71 @@ function fail(message) {
|
|
|
42
43
|
process.exit(1);
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
export function isDisconnectError(error) {
|
|
47
|
+
return error?.code === "EPIPE" || error?.code === "ERR_STREAM_DESTROYED";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function wireLauncherStdio(child, options = {}) {
|
|
51
|
+
const parentStdin = options.parentStdin ?? process.stdin;
|
|
52
|
+
const parentStdout = options.parentStdout ?? process.stdout;
|
|
53
|
+
const parentStderr = options.parentStderr ?? process.stderr;
|
|
54
|
+
const shutdownGraceMs = options.shutdownGraceMs ?? 1000;
|
|
55
|
+
|
|
56
|
+
let shutdownRequested = false;
|
|
57
|
+
let forcedShutdownTimer = null;
|
|
58
|
+
|
|
59
|
+
function clearForcedShutdownTimer() {
|
|
60
|
+
if (forcedShutdownTimer !== null) {
|
|
61
|
+
clearTimeout(forcedShutdownTimer);
|
|
62
|
+
forcedShutdownTimer = null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function requestChildShutdown() {
|
|
67
|
+
if (shutdownRequested) return;
|
|
68
|
+
shutdownRequested = true;
|
|
69
|
+
try {
|
|
70
|
+
child.stdin?.end();
|
|
71
|
+
} catch {
|
|
72
|
+
// ignore
|
|
73
|
+
}
|
|
74
|
+
forcedShutdownTimer = setTimeout(() => {
|
|
75
|
+
if (child.exitCode === null && !child.killed) {
|
|
76
|
+
try { child.kill("SIGTERM"); } catch { /* ignore */ }
|
|
77
|
+
}
|
|
78
|
+
}, shutdownGraceMs);
|
|
79
|
+
if (forcedShutdownTimer.unref) forcedShutdownTimer.unref();
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function terminateChild() {
|
|
83
|
+
clearForcedShutdownTimer();
|
|
84
|
+
if (child.exitCode === null && !child.killed) {
|
|
85
|
+
try { child.kill("SIGTERM"); } catch { /* ignore */ }
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
parentStdin.pipe(child.stdin);
|
|
90
|
+
child.stdout?.pipe(parentStdout);
|
|
91
|
+
child.stderr?.pipe(parentStderr);
|
|
92
|
+
|
|
93
|
+
parentStdin.on("end", requestChildShutdown);
|
|
94
|
+
parentStdin.on("close", requestChildShutdown);
|
|
95
|
+
parentStdin.on("error", requestChildShutdown);
|
|
96
|
+
|
|
97
|
+
const onParentOutputError = (error) => {
|
|
98
|
+
if (isDisconnectError(error)) {
|
|
99
|
+
terminateChild();
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
parentStdout.on("error", onParentOutputError);
|
|
103
|
+
parentStderr.on("error", onParentOutputError);
|
|
104
|
+
|
|
105
|
+
child.stdin?.on("error", (error) => {
|
|
106
|
+
if (!isDisconnectError(error)) throw error;
|
|
107
|
+
});
|
|
108
|
+
child.on("exit", clearForcedShutdownTimer);
|
|
109
|
+
}
|
|
110
|
+
|
|
45
111
|
function tagToDirName(tagName) {
|
|
46
112
|
const safe = String(tagName || "latest").replace(/[^a-zA-Z0-9._-]/g, "_");
|
|
47
113
|
return safe || "latest";
|
|
@@ -286,10 +352,12 @@ function launchServer(releaseDir) {
|
|
|
286
352
|
const entry = path.join(releaseDir, "dist", "index.js");
|
|
287
353
|
const child = spawn(process.execPath, [entry, ...process.argv.slice(2)], {
|
|
288
354
|
cwd: releaseDir,
|
|
289
|
-
stdio: "
|
|
355
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
290
356
|
windowsHide: false,
|
|
291
357
|
});
|
|
292
358
|
|
|
359
|
+
wireLauncherStdio(child);
|
|
360
|
+
|
|
293
361
|
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
294
362
|
process.on(signal, () => {
|
|
295
363
|
if (!child.killed) child.kill(signal);
|
|
@@ -318,6 +386,14 @@ async function main() {
|
|
|
318
386
|
launchServer(releaseDir);
|
|
319
387
|
}
|
|
320
388
|
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
389
|
+
const launchedAsScript = (() => {
|
|
390
|
+
const entry = process.argv[1];
|
|
391
|
+
if (!entry) return false;
|
|
392
|
+
return path.resolve(entry) === path.resolve(fileURLToPath(import.meta.url));
|
|
393
|
+
})();
|
|
394
|
+
|
|
395
|
+
if (launchedAsScript) {
|
|
396
|
+
main().catch((error) => {
|
|
397
|
+
fail(error instanceof Error ? error.message : String(error));
|
|
398
|
+
});
|
|
399
|
+
}
|
package/package.json
CHANGED
|
@@ -1,78 +1,79 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@harusame64/desktop-touch-mcp",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"mcpName": "io.github.Harusame64/desktop-touch-mcp",
|
|
5
|
-
"description": "LLM-native Windows computer-use MCP server with 56 tools for screenshots, UIA, mouse/keyboard, Chrome CDP, terminal, SmartScroll, and perception guards",
|
|
6
|
-
"engines": {
|
|
7
|
-
"node": ">=20.0.0"
|
|
8
|
-
},
|
|
9
|
-
"type": "module",
|
|
10
|
-
"main": "bin/launcher.js",
|
|
11
|
-
"bin": {
|
|
12
|
-
"desktop-touch-mcp": "bin/launcher.js"
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"bin/launcher.js",
|
|
16
|
-
"LICENSE",
|
|
17
|
-
"README.md",
|
|
18
|
-
"README.ja.md"
|
|
19
|
-
],
|
|
20
|
-
"publishConfig": {
|
|
21
|
-
"access": "public"
|
|
22
|
-
},
|
|
23
|
-
"napi": {
|
|
24
|
-
"name": "desktop-touch-engine",
|
|
25
|
-
"triples": {
|
|
26
|
-
"defaults": false,
|
|
27
|
-
"additional": [
|
|
28
|
-
"x86_64-pc-windows-msvc"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
|
-
"repository": {
|
|
33
|
-
"type": "git",
|
|
34
|
-
"url": "git+https://github.com/Harusame64/desktop-touch-mcp.git"
|
|
35
|
-
},
|
|
36
|
-
"bugs": {
|
|
37
|
-
"url": "https://github.com/Harusame64/desktop-touch-mcp/issues"
|
|
38
|
-
},
|
|
39
|
-
"homepage": "https://github.com/Harusame64/desktop-touch-mcp#readme",
|
|
40
|
-
"license": "MIT",
|
|
41
|
-
"scripts": {
|
|
42
|
-
"build": "tsc",
|
|
43
|
-
"sync-version": "node scripts/sync-version.mjs",
|
|
44
|
-
"check:launcher-manifest": "node scripts/check-launcher-manifest.mjs",
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"test
|
|
51
|
-
"test:
|
|
52
|
-
"test:
|
|
53
|
-
"test:
|
|
54
|
-
"test:
|
|
55
|
-
"test:e2e:
|
|
56
|
-
"test:e2e:
|
|
57
|
-
"test:e2e:
|
|
58
|
-
"test:
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"build:rs
|
|
63
|
-
"
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
"@
|
|
68
|
-
"@
|
|
69
|
-
"@
|
|
70
|
-
"@types/
|
|
71
|
-
"
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
|
|
78
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@harusame64/desktop-touch-mcp",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"mcpName": "io.github.Harusame64/desktop-touch-mcp",
|
|
5
|
+
"description": "LLM-native Windows computer-use MCP server with 56 tools for screenshots, UIA, mouse/keyboard, Chrome CDP, terminal, SmartScroll, and perception guards",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=20.0.0"
|
|
8
|
+
},
|
|
9
|
+
"type": "module",
|
|
10
|
+
"main": "bin/launcher.js",
|
|
11
|
+
"bin": {
|
|
12
|
+
"desktop-touch-mcp": "bin/launcher.js"
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"bin/launcher.js",
|
|
16
|
+
"LICENSE",
|
|
17
|
+
"README.md",
|
|
18
|
+
"README.ja.md"
|
|
19
|
+
],
|
|
20
|
+
"publishConfig": {
|
|
21
|
+
"access": "public"
|
|
22
|
+
},
|
|
23
|
+
"napi": {
|
|
24
|
+
"name": "desktop-touch-engine",
|
|
25
|
+
"triples": {
|
|
26
|
+
"defaults": false,
|
|
27
|
+
"additional": [
|
|
28
|
+
"x86_64-pc-windows-msvc"
|
|
29
|
+
]
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/Harusame64/desktop-touch-mcp.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/Harusame64/desktop-touch-mcp/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/Harusame64/desktop-touch-mcp#readme",
|
|
40
|
+
"license": "MIT",
|
|
41
|
+
"scripts": {
|
|
42
|
+
"build": "tsc",
|
|
43
|
+
"sync-version": "node scripts/sync-version.mjs",
|
|
44
|
+
"check:launcher-manifest": "node scripts/check-launcher-manifest.mjs",
|
|
45
|
+
"update-sha": "node scripts/update-sha.mjs",
|
|
46
|
+
"version": "npm run sync-version && git add src/version.ts bin/launcher.js",
|
|
47
|
+
"prepare": "tsc",
|
|
48
|
+
"start": "node dist/index.js",
|
|
49
|
+
"dev": "tsc --watch",
|
|
50
|
+
"test": "vitest run",
|
|
51
|
+
"test:capture": "node scripts/test-capture.mjs",
|
|
52
|
+
"test:unit": "vitest run --project=unit",
|
|
53
|
+
"test:e2e": "vitest run --project=e2e",
|
|
54
|
+
"test:headed": "HEADED=1 vitest run --project=e2e",
|
|
55
|
+
"test:e2e:browser": "vitest run --project=e2e \"tests/e2e/browser-*.test.ts\"",
|
|
56
|
+
"test:e2e:window": "vitest run --project=e2e tests/e2e/dock-window.test.ts tests/e2e/dock-auto.test.ts tests/e2e/focus-integrity.test.ts tests/e2e/force-focus.test.ts tests/e2e/screenshot-electron.test.ts tests/e2e/ui-elements-cache.test.ts",
|
|
57
|
+
"test:e2e:input": "vitest run --project=e2e tests/e2e/keyboard-focus-lost.test.ts tests/e2e/mouse-focus-lost.test.ts tests/e2e/terminal.test.ts",
|
|
58
|
+
"test:e2e:perception": "vitest run --project=e2e tests/e2e/perception-mvp.test.ts tests/e2e/rich-narration-edge.test.ts",
|
|
59
|
+
"test:watch": "vitest",
|
|
60
|
+
"generate:stub-catalog": "node scripts/generate-stub-tool-catalog.mjs",
|
|
61
|
+
"check:stub-catalog": "node scripts/generate-stub-tool-catalog.mjs && git diff --exit-code src/stub-tool-catalog.ts",
|
|
62
|
+
"build:rs": "napi build --platform --release && node -e \"const d=require('child_process').execSync('git diff -- index.d.ts').toString();if(d){console.warn('\\n⚠️ napi changed index.d.ts — update native-types.ts!\\n');console.warn(d)}\" && git restore --source=HEAD -- index.d.ts index.js",
|
|
63
|
+
"build:rs:debug": "napi build --platform && node -e \"const d=require('child_process').execSync('git diff -- index.d.ts').toString();if(d){console.warn('\\n⚠️ napi changed index.d.ts — update native-types.ts!\\n');console.warn(d)}\" && git restore --source=HEAD -- index.d.ts index.js",
|
|
64
|
+
"artifacts:rs": "napi artifacts"
|
|
65
|
+
},
|
|
66
|
+
"devDependencies": {
|
|
67
|
+
"@modelcontextprotocol/sdk": "^1.10.0",
|
|
68
|
+
"@napi-rs/cli": "^3.6.2",
|
|
69
|
+
"@nut-tree-fork/nut-js": "^4.2.6",
|
|
70
|
+
"@types/node": "^25.6.0",
|
|
71
|
+
"@types/ws": "^8.18.1",
|
|
72
|
+
"koffi": "^2.9.0",
|
|
73
|
+
"sharp": "^0.34.5",
|
|
74
|
+
"typescript": "^6.0.2",
|
|
75
|
+
"vitest": "^4.1.4",
|
|
76
|
+
"ws": "^8.20.0",
|
|
77
|
+
"zod": "^4.3.6"
|
|
78
|
+
}
|
|
79
|
+
}
|